在我写的一个程序中,我遇到了一些莫名其妙的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上做错了,还是编译错误?我在Windows上使用rubenvb的GCC 4.7.1(如果它有所不同,则使用std=c++11
。)
答案 0 :(得分:3)
我使用默认模板参数,这样可以推导出参数:
#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
需要在此之前推断出来。