【问题标题】:Different behaviour in C++ std::vector construction with gcc and clang使用 gcc 和 clang 在 C++ std::vector 构造中的不同行为
【发布时间】:2022-03-13 02:43:46
【问题描述】:

在下面的示例中,我希望 v 有 1 个元素,而 var 的类型将是 Vector 并将包含两个“int”Variants 10 和 20。 这是我在 gcc 中可以看到的行为。

在 clang 中,'v' 包含两个元素,即两个“int”Variants 10 和 20。

我认为 gcc 的向量是通过 initializer_list 构造函数创建的,而 clang 的向量是通过 move 构造函数创建的

这是其中一个编译器的错误吗?我是否需要将Variant 的构造函数设置为explicit(这将迫使我像Variant::Vector v{Variant{Variant::Vector{10, 20}}}; 一样使用它。如果我想保持构造函数不显式,还有其他方法可以避免这个问题吗?

https://wandbox.org/ 中的所有 gcc 和 clang 版本尝试了这段代码,它的行为相同。这里有一些链接可以直接试用:gcc,clang

#include <iostream>
#include <variant>
#include <vector>

struct Variant
{
    using Vector = std::vector<Variant>;

    Variant(const Vector & value)
    {
        var = value;
    }

    Variant(Vector && value)
    {
        var = std::move(value);
    }

    Variant(int value)
    {
        var = value;
    }

    std::variant<Vector, int> var;
};

int main()
{
    Variant::Vector v{Variant::Vector{10, 20}};

    std::cout << "v size: " << v.size() << ", index: " << v.at(0).var.index() << std::endl;

    return 0;
}

【问题讨论】:

  • fyi vs2022 说'v size: 2, index: 1'
  • 这意味着VS2022的行为和clang一样
  • 那肯定是有人错了,或者你的代码有 UB。
  • FWIW,MSVC 和 clang-cl 都 调用带有 int 参数的普通构造函数(两次)。但是 GCC 然后调用你的移动构造函数。 compiler explorer

标签: c++ gcc clang


【解决方案1】:

这里是CWG 2137,目前只有gcc实现。

Clang 错误:https://github.com/llvm/llvm-project/issues/24186

另见C++ constructor taking an std::initializer_list of size one - 这稍微复杂一点,因为初始化列表元素可从其参数(被初始化的类型)构造,但诊断是相同的,我可以'没有比 T.C. 的描述更好的了:

Clang 实现了 DR 1467(大括号从 T 初始化 T 的行为就像您没有使用大括号一样)但尚未实现 DR 2137(再想一想,只对聚合执行此操作)。

如果你可以稍微改变你的程序语法,你可以添加另一层大括号:

Variant::Vector v{{Variant::Vector{10, 20}}};

或者加括号:

Variant::Vector v({Variant::Vector{10, 20}});

【讨论】:

  • 带括号的那个不起作用,但添加另一层大括号起作用。谢谢。
猜你喜欢
  • 1970-01-01
  • 2019-06-06
  • 1970-01-01
  • 2020-10-28
  • 1970-01-01
  • 2012-07-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多