使用 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;
~~~~~~~~~~~~~~~~~~~~~~~~~~^
我试过了
- g++-5.4, g++-6.2(无错误)
- clang++-3.5,clang++-3.8,clang++-3.9(错误)
带有参数 -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>, "!"); }
在使用约束构造函数的非常简单的情况下,测试参数的可转换性,在 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
并且 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>, "!"); }