2014-09-03 12 views
9

Podobno członkowie klasy szablonu nie powinni być tworzone, chyba że są używane. Jednak ta próbka wydaje się tworzyć egzemplarz użytkownika do_something, a enable_if kończy się niepowodzeniem (czego można by się było spodziewać, gdybyśmy go stworzyli - ale AFAIK my nie).Czy członkowie klasy tworzą instancję, gdy tworzona jest klasa?

Czy brakuje mi czegoś naprawdę podstawowego?

#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

Odpowiedz

8

Od C++ 11 14.7.1/1:

Domniemana instancji klasy o specjalizacji szablonu powoduje niejawne konkretyzacji deklaracji, ale nie z definicji lub domyślnych argumentów, z funkcje klasy klasy

Deklaracja funkcji jest tworzona; która nie działa, ponieważ zależy od nieprawidłowego typu.

(Niestety, nie mam żadnych historycznych wersji standardu do ręki, ale wyobrażam sobie, zasada ta była podobna w C++ 98)

+0

@Niall: Ponieważ 'enable_if' nie ma członka o nazwie' type', gdy warunek jest fałszywy. –

+0

OK, Rozumiem, boost boost pozwala, aby typ miał osadzoną wartość, której testuje, w przeciwieństwie do std enable_if, który właśnie oczekuje stanu boolowskiego. – Niall

4

SFINAE zdarza się tylko na szablonie funkcji/metody (tutaj jest to klasa, która jest szablon),

Można to zrobić w C++ 11 (domyślny parametr szablonu dla funkcji/metoda):

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

Możesz używać alternatywnie specjalizacji, coś

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

Nie, wersja boost opcji 'enable_if' przyjmuje typ, w przeciwieństwie do wersji C++ 11. 'enable_if_c' przyjmuje typ. –

+0

@MikeSeymour: dzięki, naprawione. – Jarod42

+0

Niestety utknąłem tutaj z C++ 98, ale dobrze wiedzieć – melak47

6

Mike Seymour już odpowiedział dlaczego to nie działa , oto jak go obejść:

#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; 
} 

Szybkie zasada: Jeśli chcesz zrobić SFINAE, trzeba funkcji składowej szablonu.

Powiązane problemy