2014-09-03 3 views
9

Предполагается, что члены класса шаблона не должны создаваться, если только они не используются. Однако этот пример, как представляется, создает экземпляр элемента do_something, и ошибка enable_if (что можно было бы ожидать, если бы мы его создали, но AFAIK у нас не было).Являются ли элементы шаблона класса, созданные при создании экземпляра класса?

Я пропустил что-то действительно основное здесь?

#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

ответ

8

От C++ 11 14.7.1/1:

неявной конкретизацией шаблона класса специализации вызывает неявную экземпляров деклараций, но не из определений или аргументов по умолчанию, из функции класса-члена

Таким образом, создается декларация функции; это не работает, поскольку оно зависит от недопустимого типа.

(К сожалению, у меня нет каких-либо исторических версий стандарта на руке, но я полагаю, это правило было похоже на C++ 98)

+0

@Niall: Поскольку 'enable_if' не имеет члена, называемого' type', когда условие является ложным. –

+0

Хорошо, я понимаю, что boost_if ожидает, что тип имеет встроенное значение, которое он тестирует, в отличие от std enable_if, который просто ожидает логическое условие. – Niall

4

SFINAE происходит только на шаблон функции/метода (здесь, это ваш класс, который является шаблон),

Вы можете сделать в C++ 11 (шаблонный параметр по умолчанию для функции/метод):

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

Вы можете альтернативно использовать специализацию, что-то вроде

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

Нет, Boost версия 'enable_if' принимает тип, в отличие от версии C++ 11. 'enable_if_c' принимает тип. –

+0

@MikeSeymour: спасибо, исправлено. – Jarod42

+0

К сожалению, я застрял на C++ 98 здесь, но хорошо знаю – melak47

6

Майк Сеймур уже ответил, почему он не работает , вот как обойти это:

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

Быстрое правило: Если вы хотите сделать SFINAE, вам нужна функция член шаблона.

Смежные вопросы