c++ - 这是带有 std::any 或 std::is_copy_constructible 的 libstdc++ 中的错误,还是合法错误?

标签 c++ c++17 typetraits libstdc++ stdany

我遇到了一个相当麻烦的情况,我试图将 std::make_any 与我编写的一个类一起使用,该类在其构造函数之一中接受 std::any,但试图提出一个最小的测试用例,遇到了我认为可能是 std::any 和/或 std::is_copy_constructible 实现中的错误,但我不是 100% 确定。这里有一些最小的例子,它们在使用 g++8 和 clang++9 时有不同的工作或不工作。在每个示例中,所有相同的代码行都存在,但在 4 种状态下两行是否被注释掉,以及结果。

我使用的是 C++17 标准,通过了 -std=c++17标记为 g++-8 和 clang++-9,它们都使用 libstdc++ 版本 8.3.0 (Ubuntu 18.04)。

以下使用 g++-8 和 clang++-9 进行编译。

#include <any>
#include <type_traits>

struct Hippo {
    Hippo () { }
    Hippo (Hippo const &) { }
    Hippo (Hippo &&) { }
//     Hippo (std::any) { }
};

int main (int argc, char **argv) {
    static_assert(std::is_copy_constructible_v<Hippo>);
//     auto w = std::make_any<Hippo>();
    return 0;
}

正如人们所期望的,以下内容也适用于两者。

#include <any>
#include <type_traits>

struct Hippo {
    Hippo () { }
    Hippo (Hippo const &) { }
    Hippo (Hippo &&) { }
//     Hippo (std::any) { }
};

int main (int argc, char **argv) {
    static_assert(std::is_copy_constructible_v<Hippo>);
    auto w = std::make_any<Hippo>();
    return 0;
}

以下代码使用 g++-8 编译,但使用 clang++-9 失败。这一个令人困惑,因为 std::is_copy_constructible_v<Hippo> 的值不应通过添加与复制构造无关的构造函数来更改。

#include <any>
#include <type_traits>

struct Hippo {
    Hippo () { }
    Hippo (Hippo const &) { }
    Hippo (Hippo &&) { }
    Hippo (std::any) { }
};

int main (int argc, char **argv) {
    static_assert(std::is_copy_constructible_v<Hippo>);
//     auto w = std::make_any<Hippo>();
    return 0;
}

clang++-9给出的错误是(剪裁了长度):

/usr/bin/../lib/gcc/x86_64-linux-gnu/8/../../../../include/c++/8/type_traits:132:31: error: no member named 'value' in 'std::is_copy_constructible<Hippo>'
    : public conditional<_B1::value, _B2, _B1>::type
                         ~~~~~^
/usr/bin/../lib/gcc/x86_64-linux-gnu/8/../../../../include/c++/8/any:170:17: note: in instantiation of template class 'std::__and_<std::is_copy_constructible<Hippo>, std::is_constructible<Hippo, const Hippo &> >' requested here
      enable_if<__and_<is_copy_constructible<_Tp>,

在这里,它看起来像 std::is_copy_constructible<Hippo>类型在使用时不完整(在 <any> header 内),但它应该有一个 bool 值 constexpr value成员。这就是我认为的错误,因为 g++8 可以很好地编译它。据推测,该错误存在于 libstdc++ 的 std::any 和/或 std::is_copy_constructible 实现中,但由于 g++-8 有效而 clang++-9 失败,这令人困惑。

但是,以下代码无法在 g++-8 和 clang++-9 中编译:

#include <any>
#include <type_traits>

struct Hippo {
    Hippo () { }
    Hippo (Hippo const &) { }
    Hippo (Hippo &&) { }
    Hippo (std::any) { }
};

int main (int argc, char **argv) {
    static_assert(std::is_copy_constructible_v<Hippo>);
    auto w = std::make_any<Hippo>();
    return 0;
}

不出所料,clang++-9 产生的错误是相同的,但是 g++-8 的错误声称模板参数推导的所有候选者都对 std::any 的构造函数失败,包括应该工作但埋在其中的那个constructor 是 std::is_copy_constructible 的一个用法,所以我认为这是同样的问题,我很确定这是一个错误。我已经删除了错误消息中不相关的部分:

/usr/include/c++/8/any: In instantiation of ‘std::any std::make_any(_Args&& ...) [with _Tp = Hippo; _Args = {}]’:
.../any.cpp:13:35:   required from here
/usr/include/c++/8/any:431:14: error: no matching function for call to ‘std::any::any(const std::in_place_type_t<Hippo>&)’
       return any(in_place_type<_Tp>, std::forward<_Args>(__args)...);
              ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
<...cut for length...>
/usr/include/c++/8/any:208:7: note: candidate: ‘template<class _ValueType, class ... _Args, class _Tp, class _Mgr, typename std::enable_if<std::__and_<std::is_copy_constructible<_Tp>, std::is_constructible<_Tp, _Args&& ...> >::value, bool>::type <anonymous> > std::any::any(std::in_place_type_t<_Tp>, _Args&& ...)’
       any(in_place_type_t<_ValueType>, _Args&&... __args)
       ^~~
/usr/include/c++/8/any:208:7: note:   template argument deduction/substitution failed:
<...cut for length...>

无论如何,我的问题是——这是 libstdc++ 中的错误,对吗?

最佳答案

在全面研究这个问题时,我尝试针对 libc++(仅使用 clang++-9)而不是 libstdc++ 进行编译,这解决了问题。因此,它似乎是 libstdc++ 8.3.0 中的一个合法错误。

关于c++ - 这是带有 std::any 或 std::is_copy_constructible 的 libstdc++ 中的错误,还是合法错误?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60862278/

相关文章:

c++ - 无法从字符串流接收信息

c++ - 用于获取 C++ 中所有类型和集合的调试字符串的通用函数

c++ - tinyxml2 : how to know number of characters read successfully from a stream buffer

c++ - Qt 在两种形式之间传递值

c++ - Variadic 模板,没有匹配的调用函数

c++ - 获取 C++ 函数参数的类型

c++ - 为什么竞赛条件的输出不是随机的?

c++ - std::launder 和严格的别名规则

c++ - 作为模板参数的结构数组

c++ - 我们可以在 C++17 中检测到 "trivial relocatability"吗?