2014-09-03 5 views
9

Quando T è double(float)const Viene visualizzato questo errore quando si tenta di utilizzare function<T>.tratto da rilasciare const da un tipo di funzione membro?

implicit instantiation of undefined template 'std::function<double (float) const>' 

Ma va bene quando è Tdouble(float). Ho provato a usare std:: remove_cv<T>::type per rimuovere questo const, ma non funziona. E sì, ho #include<functional>.

Quindi la mia domanda principale è: come risolvere questo problema e rimuovere const in modo da poter inserire questo tipo di funzione in std:: function.?


mi sono imbattuto in questo problema quando si lavora con il metodo di lambda operator(), ma penso che questa domanda è in genere di qualsiasi tipo di metodo, non solo per lambda


Ma la mia seconda domanda è: Cosa vuol dire double(float)const? !! Posso capire

double (ClassName::) (float) const 

quanto significa la funzione membro non può modificare il suo ClassName oggetto. Quando inserisco questo tipo in un modello per rimuovere il tipo di classe, ricevo il double(float)const che causa problemi.

template<typename> 
struct DropClassType; 
template<typename Sig, typename C> 
struct DropClassType<Sig (C::*)> { 
    typedef Sig type_without_class; 
}; 

(clang 3.4.2 Gli errori da g ++ -. 4.9.1 sono più criptico, ma fondamentalmente la stessa)

risposta

10

Perché ho ricevuto il "istanziazione implicito del modello definito" errore?

std::function è definita come un modello di base indefinito e una specializzazione parziale che corrisponde "normali" tipi di funzione (§20.9.11.2 [func.wrap.func]):

template<class> class function; // undefined 
template<class R, class... ArgTypes> 
class function<R(ArgTypes...)> { /* ... */ }; 

double (float) const non fa corrisponde a R(ArgTypes...), quindi si ottiene il modello base non definito.


Come risolvere questo problema e rimuovere const in modo che posso mettere questo tipo di funzione in std::function?

Il trucco di specializzazione parziale standard. Mentre ci siamo, rimuoviamo anche volatile.

template<class> class rm_func_cv; // undefined 
template<class R, class... ArgTypes> 
class rm_func_cv<R(ArgTypes...)> { using type = R(ArgTypes...); }; 
template<class R, class... ArgTypes> 
class rm_func_cv<R(ArgTypes...) const> { using type = R(ArgTypes...); }; 
template<class R, class... ArgTypes> 
class rm_func_cv<R(ArgTypes...) volatile> { using type = R(ArgTypes...); }; 
template<class R, class... ArgTypes> 
class rm_func_cv<R(ArgTypes...) const volatile> { using type = R(ArgTypes...); }; 

trucchi simili possono essere utilizzati per rimuovere ref-qualificazioni, naturalmente.


Cosa significa double (float) const anche dire? !!

Questo è un angolo piuttosto oscuro dello standard (§8.3.5 [dcl.fct]/P6):

Un tipo di funzione con un cv-qualificatore-Seq o un ref-qualificatore (tra cui un tipo di nome da typedef-name (7.1.3, 14.1)) deve apparire come:

  • il tipo di funzione per una funzione membro non statica,
  • il tipo di funzione per cui un puntatore a membro riferisce,
  • la primo livello tipo funzione di una dichiarazione di funzione typedef o alias dichiarazione,
  • il tipo-id nell'argomento predefinito di un tipo-parametro (14.1), o
  • il tipo-id di a argomento modello per un parametro di tipo (14.3.1).

[Esempio:

typedef int FIC(int) const; 
    FIC f; // ill-formed: does not declare a member function 
    struct S { 
     FIC f; // OK 
    }; 
    FIC S::*pm = &S::f; // OK 

- fine esempio]

In breve, è fondamentalmente "un mezzo tipo" che è possibile utilizzare per dichiarare una funzione membro della classe o un tipo puntatore-membro (o passare come parametro modello).

+0

Cool. Quindi in realtà non significa nulla "da solo", ma può avere senso di nuovo quando viene riassociato con una classe come nei due esempi che hai dato. Esiste un tratto standard per rimuovere il const? –

+0

@AaronMcDaid Non ne sono a conoscenza. È abbastanza oscuro che dubito che qualcuno abbia pensato di scrivere un tratto per questo. –

+1

Penso che questo sarà meno oscuro in futuro grazie a lambda. Questo mi ha permesso di scrivere una funzione che prenderà qualsiasi lambda (o non generico), o oggetto simile, e lo convertirà automaticamente in un oggetto 'std :: function'. Semplicemente l'esecuzione di 'decltype (& T :: operator())' su un lambda restituirà un tipo, ma è necessario rimuovere il tipo di classe, e questo strano 'const', da quel tipo. Grazie! –

6
#include <functional> 

template <typename T> 
struct function_remove_const; 

template <typename R, typename... Args> 
struct function_remove_const<R(Args...)> 
{ 
    using type = R(Args...); 
}; 

template <typename R, typename... Args> 
struct function_remove_const<R(Args...)const> 
{ 
    using type = R(Args...); 
}; 

int main() 
{ 
    std::function<function_remove_const<double(float)const>::type> f; 
} 

Live demo link.