使用clang

时间:2016-10-08 21:19:11

标签: gcc clang c++14 sfinae typetraits

在一个非常简单的情况下,使用受约束的构造函数,测试参数的可转换性,在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;
                                                                ~~~~~~~~~~~~~~~~~~~~~~~~~~^

我已经尝试了

  • g ++ - 5.4,g ++ - 6.2(无错误)
  • clang ++ - 3.5,clang ++ - 3.8,clang ++ - 3.9(错误)
带有参数-std=c++1y

和带有-stdlib=libstdc++-stdlib=libc++的clang。

哪个编译器正确?这是clang或gcc中的错误吗?或者由于某些原因导致行为未定义,因此两个编译器正确

1 个答案:

答案 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>, "!"); }