std::reference_wrapper<std::any> 上的类型特征

Posted

技术标签:

【中文标题】std::reference_wrapper<std::any> 上的类型特征【英文标题】:Type trait on std::reference_wrapper<std::any> 【发布时间】:2019-02-28 09:45:33 【问题描述】:

std::reference_wrapper 应该是可复制构造的,无论包含的类型如何(它只是内部的一个指针)。但是,当断言使用

static_assert(std::is_copy_constructible<std::reference_wrapper<std::any> >::value, "!");

Clang 以 STL 内部的编译错误终止,而 GCC 没有报告任何问题。这不是其他类型的情况(我直接测试了std::reference_wrapper&lt;int&gt;std::any)。

我在https://godbolt.org/z/7YwkWb 有一个显示 GCC 和 Clang 编译的示例。

据我了解,即使给 std::is_copy_constructible 的类型不是可复制构造的,它也应该只给出编译时错误,而不是编译失败。 这里有什么问题?这是编译器错误还是我遗漏了什么?

来自 Clang 的编译错误是:

In file included from <source>:1:
/opt/compiler-explorer/gcc-8.2.0/lib/gcc/x86_64-linux-gnu/8.2.0/../../../../include/c++/8.2.0/type_traits:132:31: error: no member named 'value' in 'std::is_copy_constructible<std::reference_wrapper<std::any> >'
    : public conditional<_B1::value, _B2, _B1>::type
                         ~~~~~^
/opt/compiler-explorer/gcc-8.2.0/lib/gcc/x86_64-linux-gnu/8.2.0/../../../../include/c++/8.2.0/any:170:17: note: in instantiation of template class 'std::__and_<std::is_copy_constructible<std::reference_wrapper<std::any> >, std::is_constructible<std::reference_wrapper<std::any>, const std::reference_wrapper<std::any> &> >' requested here
      enable_if<__and_<is_copy_constructible<_Tp>,
                ^
/opt/compiler-explorer/gcc-8.2.0/lib/gcc/x86_64-linux-gnu/8.2.0/../../../../include/c++/8.2.0/any:175:5: note: in instantiation of template type alias '__any_constructible' requested here
    using __any_constructible_t =
    ^
/opt/compiler-explorer/gcc-8.2.0/lib/gcc/x86_64-linux-gnu/8.2.0/../../../../include/c++/8.2.0/any:181:56: note: in instantiation of template type alias '__any_constructible_t' requested here
              __any_constructible_t<_Tp, _ValueType&&> = true,
                                                       ^
/opt/compiler-explorer/gcc-8.2.0/lib/gcc/x86_64-linux-gnu/8.2.0/../../../../include/c++/8.2.0/any:183:7: note: while substituting prior template arguments into non-type template parameter [with _ValueType = const std::reference_wrapper<std::any> &, _Tp = std::reference_wrapper<std::any>, _Mgr = std::any::_Manager_internal<std::reference_wrapper<std::any> >]
      any(_ValueType&& __value)
      ^~~~~~~~~~~~~~~~~~~~~~~~~
/opt/compiler-explorer/gcc-8.2.0/lib/gcc/x86_64-linux-gnu/8.2.0/../../../../include/c++/8.2.0/type_traits:921:56: note: while substituting deduced template arguments into function template 'any' [with _ValueType = const std::reference_wrapper<std::any> &, _Tp = (no value), _Mgr = (no value), $3 = (no value), $4 = (no value)]
      : public __bool_constant<__is_constructible(_Tp, _Args...)>
                                                       ^
/opt/compiler-explorer/gcc-8.2.0/lib/gcc/x86_64-linux-gnu/8.2.0/../../../../include/c++/8.2.0/type_traits:933:14: note: in instantiation of template class 'std::is_constructible<std::reference_wrapper<std::any>, const std::reference_wrapper<std::any> &>' requested here
    : public is_constructible<_Tp, const _Tp&>
             ^
/opt/compiler-explorer/gcc-8.2.0/lib/gcc/x86_64-linux-gnu/8.2.0/../../../../include/c++/8.2.0/type_traits:939:14: note: in instantiation of template class 'std::__is_copy_constructible_impl<std::reference_wrapper<std::any>, true>' requested here
    : public __is_copy_constructible_impl<_Tp>
             ^
<source>:12:20: note: in instantiation of template class 'std::is_copy_constructible<std::reference_wrapper<std::any> >' requested here
static_assert(std::is_copy_constructible<std::reference_wrapper<std::any> >::value, "!");
                   ^
In file included from <source>:1:
/opt/compiler-explorer/gcc-8.2.0/lib/gcc/x86_64-linux-gnu/8.2.0/../../../../include/c++/8.2.0/type_traits:137:31: error: no member named 'value' in 'std::is_copy_constructible<std::reference_wrapper<std::any> >'
    : public conditional<_B1::value, __and_<_B2, _B3, _Bn...>, _B1>::type
                         ~~~~~^
/opt/compiler-explorer/gcc-8.2.0/lib/gcc/x86_64-linux-gnu/8.2.0/../../../../include/c++/8.2.0/any:192:27: note: in instantiation of template class 'std::__and_<std::is_copy_constructible<std::reference_wrapper<std::any> >, std::__not_<std::is_constructible<std::reference_wrapper<std::any>, const std::reference_wrapper<std::any> &> >, std::__not_<std::__is_in_place_type<std::reference_wrapper<std::any> > > >' requested here
              enable_if_t<__and_<is_copy_constructible<_Tp>,
                          ^
/opt/compiler-explorer/gcc-8.2.0/lib/gcc/x86_64-linux-gnu/8.2.0/../../../../include/c++/8.2.0/any:196:7: note: while substituting prior template arguments into non-type template parameter [with _ValueType = const std::reference_wrapper<std::any> &, _Tp = std::reference_wrapper<std::any>, _Mgr = std::any::_Manager_internal<std::reference_wrapper<std::any> >]
      any(_ValueType&& __value)
      ^~~~~~~~~~~~~~~~~~~~~~~~~
/opt/compiler-explorer/gcc-8.2.0/lib/gcc/x86_64-linux-gnu/8.2.0/../../../../include/c++/8.2.0/type_traits:921:56: note: while substituting deduced template arguments into function template 'any' [with _ValueType = const std::reference_wrapper<std::any> &, _Tp = (no value), _Mgr = (no value), $3 = (no value)]
      : public __bool_constant<__is_constructible(_Tp, _Args...)>
                                                       ^
/opt/compiler-explorer/gcc-8.2.0/lib/gcc/x86_64-linux-gnu/8.2.0/../../../../include/c++/8.2.0/type_traits:933:14: note: in instantiation of template class 'std::is_constructible<std::reference_wrapper<std::any>, const std::reference_wrapper<std::any> &>' requested here
    : public is_constructible<_Tp, const _Tp&>
             ^
/opt/compiler-explorer/gcc-8.2.0/lib/gcc/x86_64-linux-gnu/8.2.0/../../../../include/c++/8.2.0/type_traits:939:14: note: in instantiation of template class 'std::__is_copy_constructible_impl<std::reference_wrapper<std::any>, true>' requested here
    : public __is_copy_constructible_impl<_Tp>
             ^
<source>:12:20: note: in instantiation of template class 'std::is_copy_constructible<std::reference_wrapper<std::any> >' requested here
static_assert(std::is_copy_constructible<std::reference_wrapper<std::any> >::value, "!");
                   ^
2 errors generated.
Compiler returned: 1

【问题讨论】:

请在您的问题中包含编译器错误。 关于“...而不是编译失败”:static_assert 的全部意义在于编译时失败,如果您只想查看值,请不要将其放入 @987654329 @ user463035818:你说得对。但是 Clang 中的编译不会因为 static_assert 失败而失败。如果我删除 static_assert 或者我否定这个论点,它也会失败。问题是在评估 static_assert 的 (constexpr) 参数时出错。 是的,我只是认为static_assert 有点牵强,你的句子是错误的/有点误导。如果您提供给std::is_copy_constructible 的类型不是可复制构造的,您将获得编译时错误,并且代码将在编译时失败(因为静态断言) 【参考方案1】:

您看到的错误在顶部清楚地表明std::is_copy_constructible 没有您检查的专业化的value 成员。现在,您传递的类型不会违反std::is_copy_constructible 的约定,因此不存在未定义行为的风险。

这仅意味着一件事,它不是编译器问题,而是标准库实现问题。 Clang 使用默认安装的标准库实现,在godbolt 运行的系统上是libstdc++(GNU 实现)。由于某些可能的软不兼容,这显然会导致问题。

如果您在使用 Clang 构建时指定了 -stdlib=libc++ 选项(libc++ 是标准库的 LLVM 实现),那么它可以正常接受代码。

【讨论】:

这是有道理的。我没有考虑过STL。但是:Clang 不应该能够使用标准库的 GNU 实现进行编译吗? @ephimetheus - 通常。每个标准库版本都更适合一个编译器。有时,它可能会导致问题,如您所见。

以上是关于std::reference_wrapper<std::any> 上的类型特征的主要内容,如果未能解决你的问题,请参考以下文章

我可以实例化一个 std::reference_wrapper<T> ,其中 T 是不完整的类型吗?

std::reference_wrapper 中的 Visual C++ 10.0 错误?

是否可以仅从 std::any 使用 std::reference_wrapper 创建 std::any?

非模板 std::reference_wrapper 赋值运算符和模板构造函数

在 std::map 中搜索时堆栈溢出

无法在 Clang 上将 std::reference<T> 转换为 std::reference<const T>