Выбрать конструктор класса, используя включить, если
Рассмотрим следующий код:
#include <iostream>
#include <type_traits>
template <typename T>
struct A {
int val = 0;
template <class = typename std::enable_if<T::value>::type>
A(int n) : val(n) {};
A(...) { }
/* ... */
};
struct YES { constexpr static bool value = true; };
struct NO { constexpr static bool value = false; };
int main() {
A<YES> y(10);
A<NO> n;
std::cout << "YES: " << y.val << std::endl
<< "NO: " << n.val << std::endl;
}
Я хочу выборочно определить конструктор A:: A (int) только для некоторых типов, используя enable_if. Для всех остальных типов существует конструктор по умолчанию A:: A(...) который должен быть по умолчанию для компилятора, когда подстановка завершается неудачей. Однако это имеет смысл для меня компилятор (gcc версии 4.9.0 20130714) все еще жалуется
Sfinae.cpp: в экземпляре 'struct A': sfinae.cpp: 19: 11:
требуется sfinae.cpp: 9: 5: ошибка: нет тип с именем 'type' в
'struct std:: enable_if'
A (int n): val (n) {};
Возможно ли что-то подобное для конструктора? Возможно ли это с другими конструкторами (конструкторами копирования и перемещения)?
2 ответа:
Я думаю, что это не может работать с одним параметром шаблона по умолчанию, потому что его значение должно быть разрешено при создании экземпляра шаблона класса.
Нам нужно отложить подстановку до момента создания экземпляра шаблона конструктора. Один из способов-установить параметр шаблона по умолчанию в значение T и добавить дополнительный фиктивный параметр в конструктор:
template<typename U = T> A(int n, typename std::enable_if<U::value>::type* = 0) : val(n) { }
обычно это делается с помощью анонимного дефолтного аргумента:A(int n, typename std::enable_if<T::value>::type* = 0) : val(n) {};
Вы не можете использовать параметры шаблона из класса для SFINAE out методов. Таким образом, один из способов-добавить фиктивный тип, заменяющий int:
#include <iostream> #include <type_traits> template <typename T> struct A { int val = 0; template<typename Integer ,typename = typename std::enable_if<T::value && sizeof(Integer)>::type > A(Integer n) : val(n) {}; A(...) {} /* ... */ }; struct YES { constexpr static bool value = true; }; struct NO { constexpr static bool value = false; }; int main() { A<YES> y(10); A<NO> n; std::cout << "YES: " << y.val << std::endl << "NO: " << n.val << std::endl; }
Это работает, потому что вы используете параметр шаблона члена для SFINAE из конструктора, но тест всегда истинен, поэтому он не загрязняет ваши проверки