在一个非常简单的情况下,使用受约束的构造函数,测试参数的可转换性,在clang中产生错误,但不是在g ++中产生错误:
#include <type_traits>
template <class T, class U>
constexpr bool Convertible = std::is_convertible<T,U>::value && std::is_convertible<U,T>::value;
template <class T>
struct A
{
template <class S, class = std::enable_if_t<Convertible<S,T>> >
A(S const&) {}
};
int main()
{
A<double> s = 1.0;
}
也许这个问题与Is clang's c++11 support reliable?
有关错误clang给出,读取:
error: no member named 'value' in 'std::is_convertible<double, A<double> >'
constexpr bool Convertible = std::is_convertible<T,U>::value && std::is_convertible<U,T>::value;
~~~~~~~~~~~~~~~~~~~~~~~~~~^
我已经尝试了
-std=c++1y
的和带有-stdlib=libstdc++
或-stdlib=libc++
的clang。
哪个编译器正确?这是clang或gcc中的错误吗?或者由于某些原因导致行为未定义,因此两个编译器正确?
答案 0 :(得分:3)
首先,请注意,如果使用:
,它可以正常工作A<double> s{1.0};
相反,错误来自于您这样做的事实:
A<double> s = 1.0;
考虑下面的一行(摘自Convertible
的定义):
std::is_convertible<U,T>::value
在你的情况下,这是看到,因为它遵循(一旦替换已经执行):
std::is_convertible<double, A<double>>::value
编译器在错误消息中明确说明了这一点。
这是因为从A<double>
构建了一个临时1.0
,然后将其分配给s
。
请注意,在您的类模板中,您已经定义了一个(或多或少)catch-all构造函数,因此也接受const A<double> &
。
此外,请记住临时绑定到const引用。
也就是说,错误发生是因为在std::enable_if_t
的上下文中我们A<double>
是一个不完整的类型,而且从标准我们得到std::is_convertible
:
From和To应为完整类型[...]
有关工作草案,请参阅here。
因此,我会说这是未定义的行为。
作为建议,在这种情况下您不需要使用std::enable_if_t
在您的示例中,您没有一组函数可以从中选择最佳函数
static_assert
很好,错误消息更好:
template <class S>
A(S const&) { static_assert(Convertible<S,T>, "!"); }