Проблемы с enable_if SFINAE
У меня возникли необъяснимые проблемы с SFINAE в программе, которую я пишу, поэтому я свел ее к отдельному примеру программы:
#include <type_traits>
struct Base { };
struct Derived : public Base { };
template<typename T>
struct From { };
template<typename T>
struct To {
template<typename U>
To(const From<U>& other) {
static_assert(std::is_convertible<U*, T*>::value, "error");
}
};
int main() {
From<Derived> a;
To<Base> b = a;
}
Эта программа компилируется без ошибок или предупреждений. Однако это:
#include <type_traits>
struct Base { };
struct Derived : public Base { };
template<typename T>
struct From { };
template<typename T>
struct To {
template<typename U>
To(const From<typename std::enable_if<true, U>::type>& other) {
// this ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
static_assert(std::is_convertible<U*, T*>::value, "error");
}
};
int main() {
From<Derived> a;
To<Base> b = a;
}
Выдает следующую ошибку:
test.cpp: в функции
int main()
:test.cpp: 22: 18: ошибка: преобразование из
From<Base>
к нескалярному типуTo<Derived>
запрошенный
Я полагаю, что замена не удалась, а конструктор не виден.
Я делаю SFINAE неправильно, или это ошибка компилятора? Я использую GCC 4.7.1 Rubenvb на Windows (с std=c++11
если это имеет значение).
1 ответ
Я бы использовал аргумент шаблона по умолчанию, таким образом аргумент может быть выведен:
#include <type_traits>
struct Base { };
struct Derived : public Base { };
template<typename T>
struct From { };
template<typename T>
struct To {
template<typename U, class = typename std::enable_if<true, U>::type>
To(const From<U>& other) {
// this ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
static_assert(std::is_convertible<U*, T*>::value, "error");
}
};
int main() {
From<Base> a;
To<Derived> b = a;
}
Обратите внимание, что это вызывает static_assert
потерпеть неудачу, так как вы используете std::is_convertible
наоборот. Так должно быть:
static_assert(std::is_convertible<T*, U*>::value, "error");
В вашем примере тип шаблона U
не может быть выведено. В моем коде это может быть выведено, так как он используется в качестве аргумента шаблона для other
аргумент в конструкторе. В вашем коде компилятор видит std::enable_if<true, U>::type
и не могу понять, что это U
Тип есть. Тот факт, что результатом этого enable_if
используется в качестве аргумента шаблона для From
не помогает вообще, так как U
нужно выводить до этого.