2016-05-18 4 views
1

Я понятия не имею, какие правила следует использовать для использования SFINAE для перегрузки метода. Я запускаю несколько раз в проблемах, потому что там, где я знаю, есть больше правил. Поэтому я надеюсь, что существует ряд правил, которые можно кратко объяснить, чтобы помочь решить проблемы в целом, а не задавать вопросы снова и снова.Перегрузка SFINAE, правила которой должны быть рассмотрены

Моя точка старта здесь: Specializing class with SFINAE if a parameter pack is needed

Код 1

class AA { public: using TRAIT = int; }; 
class BB { public: using TRAIT = float; }; 

template < typename T> 
class Y 
{ 
    public: 
     template <typename U = T, typename V= typename std::enable_if< std::is_same< int, typename U::TRAIT>::value, int >::type> 
      Y() { std::cout << "First" << std::endl; } 

     template <typename U = T, typename V= typename std::enable_if< !std::is_same< int, typename U::TRAIT>::value, float >::type> 
      Y() { std::cout << "Second" << std::endl; } 

}; 

error: 'template template Y::Y()' cannot be overloaded

К этой проблеме я получил комментарий:

"the "constructor cannot be overloaded" problem can be solved by adding a dummy and defaulted template parameter (like , typename Z = void) to one of the constructors"

OK, изменяя свой код по:

Код 2

template < typename T> 
class Y 
{ 
    public: 
     template <typename U = T, typename V= typename std::enable_if< std::is_same< int, typename U::TRAIT>::value, int >::type, typename X=int> 
      Y(X* = nullptr) { std::cout << "First" << std::endl; } 

     template <typename U = T, typename V= typename std::enable_if< !std::is_same< int, typename U::TRAIT>::value, float >::type> 
      Y() { std::cout << "Second" << std::endl; } 
}; 

ОК, он компилирует. Но упрощение швов к работам также делает меня сомнительным.

Код 3

template < typename T> 
class Y 
{ 
    public: 
     template <typename U = T, typename V= typename std::enable_if< std::is_same< int, typename U::TRAIT>::value, int >::type> 
      Y(int* = nullptr) { std::cout << "First" << std::endl; } 

     template <typename U = T, typename V= typename std::enable_if< !std::is_same< int, typename U::TRAIT>::value, float >::type> 
      Y() { std::cout << "Second" << std::endl; } 
}; 

Последний пример также работает! Он имеет параметр по умолчанию в ONE из конструкторов, но этот параметр не является шаблоном.

Для меня сейчас совершенно неясно, какие правила работают, чтобы заставить вещи работать здесь.

Мое первое недоразумение в том, что я думал, что SFINAE имеет место путем создания экземпляра шаблона конструктора и становится доступным только один конструктор. Это не правда! Каждый набор параметров для всех конструкторов должен быть другим !? Зачем? И, кроме того, почему он должен или должен быть шаблонным параметром? Мой пример 3 швов для работы, но другие дали мне совет использовать dummy and defaulted template parameter (like , typename Z = void). Может ли кто-нибудь дать мне немного справочной информации по этой теме?

+0

http://stackoverflow.com/a/36500292/3953764 –

+0

* «Я думал, что SFINAE имеет место, создавая экземпляр шаблона конструктора, и доступен только один конструктор. Это не правда!» * => Но вы получаете ошибку даже без определения AA или BB. Таким образом, проблема не связана с созданием шаблона. Повторяя уже сказанное: это так же, как «void foo (bool b = false)» и «void foo (bool b = true)» не могут сосуществовать в определении только потому, что у них разные значения по умолчанию. Таким образом, это с ' и' '. – HostileFork

ответ

5

Подпись функции должна быть разной, а значение по умолчанию (для шаблона как для обычного аргумента) не является частью подписи. Так

template <typename U = T, typename V= typename std::enable_if< std::is_same< int, typename U::TRAIT>::value, int >::type> 
Y(); 

template <typename U = T, typename V= typename std::enable_if< !std::is_same< int, typename U::TRAIT>::value, float >::type> 
Y(); 

просто

template <typename U, typename V> 
Y(); 

template <typename U, typename V> 
Y(); 

Итак, redifinition.

В то время как

template <typename U = T, typename V = typename std::enable_if< std::is_same< int, typename U::TRAIT>::value, int >::type, typename X=int> 
Y(X* = nullptr); 

template <typename U = T, typename V= typename std::enable_if< !std::is_same< int, typename U::TRAIT>::value, float >::type> 
Y(); 

являются

template <typename U, typename V, typename X> 
Y(X*); 

template <typename U, typename V> 
Y(); 

и поэтому разные подписи.

Обойти всегда добавлять параметр, чтобы сделать что-то вроде

template <typename U = T, typename std::enable_if<std::is_same<int, typename U::TRAIT>::value>::type* = nullptr> 
Y(); 

template <typename U = T, typename std::enable_if<!std::is_same<int, typename U::TRAIT>::value>::type* = nullptr> 
Y(); 

, которые приводят к различным подписи:

template <typename U, typename std::enable_if<std::is_same<int, typename U::TRAIT>::value>::type*> 
Y(); 

template <typename U, typename std::enable_if<!std::is_same<int, typename U::TRAIT>::value>::type*> 
Y(); 
+0

Последний пример «простого» использования указателя начального типа по умолчанию для меня странный. Я думал, что это заканчивается в 'template ', который также является одним и тем же для обоих определений. Можете ли вы добавить короткое объяснение, почему здесь подпись расширяется с полным выражением конструкции SFINAE? – Klaus

+0

@Klauss, даже если 'std :: enable_if_t <..> *' приводит к 'void *' для обоих, это другая подпись (раньше). Но если они оба приводят к 'void *' для некоторого 'T', у вас будет неоднозначный вызов в любом случае. поэтому условие следует выбирать осторожно (некоторые пишут 'disable_if' помощник, чтобы записать одно и то же условие в обоих). – Jarod42

+0

@Klauss Впервые увидев этот материал, я подумал, что было бы полезно вставить 'static_assert (std :: is_same :: значение,« не может явно параметризовать шаблон »);« Просто ради того, чтобы понять, что там является степенью свободы здесь, в вызове, который вы не хотите использовать людям, чтобы переопределить значение по умолчанию U = T, которое было выбрано только для SFINAE. * (Хотя для этого специально вы [не можете явно параметризовать шаблонные конструкторы] (http://stackoverflow.com/a/2786963/211160).) * Так, например, 'Y yaa; yaa.foo (); ' – HostileFork

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