用gcc和clang构造C++std::向量时的不同行为



在下面的例子中,我希望v有1个元素,其var的类型为Vector,并包含两个";int";CCD_ 4的10和20。这就是我在gcc中看到的行为。

对于clang,"v"包含两个元素;int";CCD_ 5的10和20。

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

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

在中的所有gcc和clang版本中尝试了此代码https://wandbox.org/并且它的行为是相同的。以下是一些可以直接尝试的链接: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;
}

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

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

另请参阅C++构造函数采用大小为1的std::initializer_list-这稍微复杂一点,因为initializer-list元素可以从的参数(被初始化的类型(中构造,但诊断是一样的,我不能比t.C.的描述做得更好:

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

如果你可以稍微更改程序语法,你可以添加另一个级别的大括号:

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

或者加括号:

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

最新更新