2015-06-03 19 views
6

Perché non è possibile dedurre F per proxy()?Impossibile dedurre argomento modello che è una funzione

Dovrebbe essere possibile perché lo sto restringendo, solo per le funzioni che restituiscono uno int.

#include <utility> 
#include <iostream> 
#include <type_traits> 
using namespace std; 

int foo(int bar) { 
    cout << "int" << endl; 
    return 2; 
} 

float foo(float bar) { 
    cout << "float" << endl; 
    return 1; 
} 

template <typename F, typename... Args> 
typename enable_if< 
    is_same< 
     typename result_of<F(Args...)>::type, 
     int 
     >::value, 
    typename result_of<F(Args...)>::type 
    >::type 
proxy(F func, Args&&... args) { 
    return func(forward<Args>(args)...); 
} 

int main() { 
    proxy(foo, 5); 
} 

Ecco l'errore:

b.cpp:29:17: error: no matching function for call to 'proxy(<unresolved overloaded function type>, int)' 
b.cpp:24:1: note: template argument deduction/substitution failed: 
b.cpp:29:17: note: couldn't deduce template parameter 'F' 
+0

Come ci sono due overload della funzione ... compilatore non può dedurre il valore sulla base di un futuro (successivo) parametro di una funzione ...'proxy (static_cast (foo), 5);' farebbe il trucco qui –

risposta

4

Il problema è questo:

proxy(foo, 5); 

Il compilatore cerca di dedurre il tipo di foo, ma ci sono 2 sovraccarichi. Ovviamente, è possibile dedurre Args... da 5, ma il tipo di foo è ancora non deducibile, poiché il compilatore non sa quale sovraccarico selezionare quando si esegue la deduzione del tipo.

Si noti che il compilatore deve conoscere il tipo di F nella firma della funzione, vale a dire qui, quindi SFINAE fare la sua magia:

is_same< 
    typename result_of<F(Args...)>::type, 
    int 
>::value, 

Non c'è assolutamente alcun modo per poter dedurre correttamente il tipo di di F dalla chiamata proxy(foo, 5), quindi SFINAE non può eseguire l'accesso. Come nota a margine, si noti che C++ non può sovraccaricare solo in base al tipo restituito. Quindi non sarai in grado di differenziare due funzioni con lo stesso nome basandoti esclusivamente sul tipo di ritorno. Avrai bisogno in qualche modo di forzare una corrispondenza dei parametri che consentirà a SFINAE di superare i sovraccarichi non candidati.

in qualche modo legati: Deducing the return type of a standalone function

E una citazione rilevante dallo standard, sottolineare la mia (grazie a @TC per segnalarlo):

14.8.2.1 dedurre argomenti di template da una chiamata di funzione [Temp .deduct.call]/(6,2)

(6) When P is a function type, pointer to function type, or pointer to member function type:

  • (6.1) If the argument is an overload set containing one or more function templates, the parameter is treated as a non-deduced context.

  • (6.2) If the argument is an overload set (not containing function templates), trial argument deduction is attempted using each of the members of the set. If deduction succeeds for only one of the overload set members, that member is used as the argument value for the deduction. If deduction succeeds for more than one member of the overload set the parameter is treated as a non-deduced context.

+0

ma perché non prova con ognuno di essi e guarda quanto lontano otterrebbe nel modello di istanziazione/sostituzione ? C'è un modo per ovviare a questo senza un cast esplicito? – onqtam

+0

@onqtam Immagino sia troppo complicato, per il compilatore il primo parametro 'F' non ha nulla a che fare con il secondo' Args ... '. Proverò a pensare a una soluzione alternativa. – vsoftco

+0

Questo problema è riproducibile senza gli argomenti - solo quando si utilizza il tipo restituito ... Credo che avrei dovuto inserire un esempio più semplice – onqtam

2

Nel tuo esempio foo nomi di una serie di funzioni sovraccaricate, e il modello argomento deduzione è in grado di selezionare o ne sovraccarico su un altro perché sono entrambe le partite di pari rango.

L'assegno vincolo SFINAE non calci fino a dopo F è stata dedotta, quindi è di alcun aiuto per far cadere float foo(float) dal set la risoluzione di sovraccarico.

Supponiamo che l'utente abbia rinominato la funzione restituendo float in foof, quindi l'esempio verrà compilato. Tuttavia, se si è tentato di chiamare proxy con foof come argomento della funzione, il codice non riuscirà nuovamente a compilare, questa volta a causa del vincolo enable_if.

per ottenere il vostro esempio per compilare nel suo stato attuale è necessario disambiguare che foo siete di passaggio a proxy

proxy(static_cast<int(*)(int)>(foo), 5); 
+0

Immagino di non capire ancora bene la SFINAE perché pensavo che mi avrebbe aiutato qui ... – onqtam

Problemi correlati