使用 clang 时 std::is_convertible 中没有成员命名值

No member named value in std::is_convertible when using clang

在使用约束构造函数的非常简单的情况下,测试参数的可转换性,在 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 并且 clang 带有 -stdlib=libstdc++-stdlib=libc++.

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

首先请注意,如果您使用:

A<double> s{1.0};

相反,错误来自于您这样做的事实:

A<double> s = 1.0;

考虑以下行(从 Convertible 的定义中提取):

std::is_convertible<U,T>::value

在你的情况下,这是 看到的 如下(执行替换后):

std::is_convertible<double, A<double>>::value

编译器在错误信息中说的很清楚。

这是因为1.0构造了一个临时的A<double>,然后赋值给了s
请注意,在您的 class 模板中,您定义了一个(或多或少)包罗万象的构造函数,因此 const A<double> & 也被接受。
此外,请记住临时绑定到常量引用。

就是说,错误发生是因为在 std::enable_if_t 的上下文中我们有 A<double> 是一个不完整的类型,并且根据标准我们有 std::is_convertible 的这个:

From and To shall be complete types [...]

请参阅 here 工作草案。

因此,我会说这是一个 未定义的行为


作为建议,在这种情况下您不需要使用 std::enable_if_t
您没有一组函数可以从您的示例中挑选出最好的一个。
static_assert 很好,错误消息更好:

template <class S> 
A(S const&) { static_assert(Convertible<S,T>, "!"); }