【问题标题】:No member named value in std::is_convertible when using clang使用 clang 时 std::is_convertible 中没有成员命名值
【发布时间】:2016-10-08 21:19:11
【问题描述】:

在一个非常简单的情况下,使用受约束的构造函数,测试参数的可转换性,在 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还是gcc中的错误?还是由于某些原因导致行为未定义,因此两个编译器都正确

【问题讨论】:

    标签: gcc clang c++14 sfinae typetraits


    【解决方案1】:

    首先,请注意,如果您使用它可以正常工作:

    A<double> s{1.0};
    

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

    A<double> s = 1.0;
    

    考虑下面一行(摘自Convertible的定义):

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

    在你的情况下,这是 seen 如下(一旦执行替换):

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

    编译器在错误消息中清楚地说明了这一点。

    这是因为一个临时的A&lt;double&gt;是由1.0构造的,然后分配给s
    请注意,在您的类模板中,您已经(或多或少)定义了一个包罗万象的构造函数,因此也接受了 const A&lt;double&gt; &amp;
    此外,请记住临时绑定到 const 引用。

    也就是说,发生错误是因为在 std::enable_if_t 的上下文中,我们认为 A&lt;double&gt; 是一个不完整的类型,而从标准来看,我们为 std::is_convertible 提供了这个:

    From 和 To 应该是完整类型 [...]

    有关工作草案,请参阅here

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


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

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

    【讨论】:

    • 非常感谢!这向我解释了很多。 “包罗万象”的论点和构造路径是我的洞察力,并在更大的上下文中导致了解决方案(原始代码包含许多不同的模板化构造函数,因此错误消息方法无法启动)跨度>
    • 那么为什么std::is_convertible&lt;double, A&lt;double&gt;&gt; 没有::value 成员?我认为它应该有一个 value 成员 false?
    • 我想我现在明白了。我猜是因为std::is_convertible&lt;double, A&lt;double&gt; &gt;的实现要成功,它需要测试A&lt;double&gt;的构造函数是否接受double,它递归地需要在自己的定义中实现std::is_convertible&lt;double, A&lt;double&gt; &gt;,此时错误出现是因为std::is_convertible&lt;double, A&lt;double&gt; &gt; 本身在那里不完整。
    • 我是因为实施的原因才回复的,但我不在电脑上,无法验证。你做到了,非常感谢!! ;-)
    猜你喜欢
    • 2018-11-20
    • 2014-09-26
    • 1970-01-01
    • 1970-01-01
    • 2017-02-13
    • 2012-06-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多