2014-09-03 17 views
9

Presumibilmente i membri di una classe template non dovrebbero essere istanziati a meno che non vengano utilizzati. Tuttavia, questo esempio sembra creare un'istanza del membro do_something e l'errore enable_if (che ci si aspetterebbe se lo avessimo istanziato, ma AFAIK non l'abbiamo fatto).I membri di un modello di classe sono istanziati quando viene creata un'istanza della classe?

Mi manca qualcosa di veramente semplice qui?

#include <string> 
#include <boost/utility.hpp> 

struct some_policy { 
    typedef boost::integral_constant<bool, false> condition; 
}; 

struct other_policy { 
    typedef boost::integral_constant<bool, true> condition; 
}; 


template <typename policy> 
class test { 
    void do_something(typename boost::enable_if<typename policy::condition>::type* = 0) {} 
}; 

int main() { 
    test<other_policy> p1; 
    test<some_policy> p2; 
} 

coliru

risposta

8

Da C++ 11 14.7.1/1:

l'istanza implicita di una specializzazione template di classe fa sì che l'implicita esemplificazione delle dichiarazioni, ma non delle definizioni o argomenti di default, del funzioni membro della classe

Quindi la dichiarazione di funzione viene istanziata; non funziona poiché dipende da un tipo non valido.

(Purtroppo, non ho le versioni storiche della norma a portata di mano, ma immagino che questa regola è stata simile in C++ 98)

+0

@Niall: Poiché 'enable_if' non ha un membro chiamato' type' quando la condizione è falsa. –

+0

Ok, ho capito, il boost enable_if si aspetta che il tipo abbia un valore incorporato per il quale prova, diversamente da std enable_if, che si aspetta solo la condizione booleana. – Niall

4

SFINAE avviene solo sulla funzione template/metodo (qui, è la classe che è modello),

Si può fare in C++ 11 (parametro di modello predefinito per la funzione/metodo):

template <typename policy> 
class test { 
    template <typename T = policy> 
    void do_something(typename boost::enable_if<typename T::condition>::type* = 0) {} 
}; 

E 'possibile in alternativa utilizzare la specializzazione, qualcosa come

template <bool> struct helper_do_something {}; 
template <> struct helper_do_something<true> 
{ 
    void do_something() { /* Your implementation */ } 
}; 

template <typename policy> 
class test : helper_do_something<T::condition::value> 
{ 
    // do_something is inherited (and it is present only when T::condition::value is true) 
}; 
+2

No, la versione Boost di 'enable_if' richiede un tipo, a differenza della versione C++ 11. 'enable_if_c' accetta un tipo. –

+0

@MikeSeymour: grazie, risolto. – Jarod42

+0

Purtroppo sono bloccato con C++ 98 qui, ma buono a sapersi – melak47

6

Mike Seymour già risposto perché non funziona , ecco come soluzione alternativa è:

#include <string> 
#include <boost/utility.hpp> 

struct some_policy { 
    typedef boost::integral_constant<bool, false> condition; 
}; 

struct other_policy { 
    typedef boost::integral_constant<bool, true> condition; 
}; 

template <typename policy> 
class test { 
private: 

    template<typename P> 
    void do_something_impl(typename boost::enable_if<typename P::condition>::type* = 0) {} 

public: 
    void do_something() 
    { 
     do_something_impl<policy>();  
    } 
}; 

int main() { 
    test<other_policy> p1; 
    test<some_policy> p2; 
} 

regola rapida generale: se si vuole fare SFINAE, hai bisogno di una funzione membro modello.

Problemi correlati