我如何解决 C++ 中使用列表初始化器的大括号省略的歧义?

问题描述

我想为 3x3 矩阵制作自己的结构。我想允许通过组件/元素或“行”进行构建。

因此,您可以提供 std::array<float,9>std::array<std::array<float,3>,3>

但是,当使用以下构造函数定义这样的结构时:

struct Matrix3x3
{
    Matrix3x3(std::array<float,9> components) { }

    Matrix3x3(std::array<std::array<float,3> rows) { }
};

然后第二个构造函数与第一个构造函数有歧义。这意味着您可以像这样调用第二个构造函数

Matrix3x3{ {{ {{1.f,2.f,3.f}},{{4.f,5.f,6.f}},{{7.f,8.f,9.f}} }} };

没有任何问题,但是像这样调用一个构造函数

Matrix3x3{ {{1.f,3.f,4.f,6.f,7.f,9.f}} };

将给出以下消息和错误

message : No constructor Could take the source type,or constructor overload resolution was ambiguous
error C2440: '<function-style-cast>': cannot convert from 'initializer list' to 'ArrayTest'

Visual Studio 告诉我“有不止一个构造函数实例......匹配参数列表”。

我测试了做同样的事情,但使用了一个整数数组(因为它更容易使用)和一个长度。考虑:

struct ArrayTest
{
    ArrayTest(std::array<int,1> arrayOfInts) { }

    ArrayTest(std::array<std::array<int,1>,1> arrayOfArraysOfInts) { }
};

那么前 3 个是有效的,并为第一个构造函数编译,而所有 5 个都为第二个构造函数编译。

auto test1 = ArrayTest{ {1} };

auto test2 = ArrayTest{ { {1} } };

auto test3 = ArrayTest{ { { {1} } } };

auto test4 = ArrayTest{ { { { {1} } } } };

auto test5 = ArrayTest{ { { { { {1} } } } } };

对于简单的数组构造函数“test3”是完整的初始化,其中第一对括号初始化聚合ArrayTest,第二对初始化数组,第三对初始化该数组的第一个元素,最后是第四个括号初始化整数 1,这很少见,但有效。 “test1”和“test2”只是“test3”的括号省略版本。

对于array-of-arrays 构造函数,它是类似的,其中“test5”是完整的初始化,所有其他的都是花括号省略的。这就是造成歧义的原因。

所以问题是:我该如何解决这个问题?或者有更好的方法/解决方案吗?

解决方法

解决此问题的一种方法是单独声明和定义临时数组,如下所示:

std::array<float,9> components{ 1.f,2.f,3.f,4.f,5.f,6.f,7.f,8.f,9.f };

std::array<float,3> row1{ 1.f,3.f };
std::array<float,3> row2{ 4.f,6.f };
std::array<float,3> row3{ 7.f,9.f };

Matrix3x3 m1{ components };
Matrix3x3 m2{ { row1,row2,row3} };

这避免了使用列表初始值设定项进行大括号省略的歧义,但是这相当乏味并且似乎不是“最佳”,因为从那时起您正在构建临时数组,只是为了构建其他东西,而列表的重点-在这种情况下,初始化将避免这些。

,

使用标签:一个空的结构体,例如,struct by_row{};。然后您的逐行构造函数将其作为第一个参数,另一个则没有。类似于 <algorithm> 中的算法如何将“执行策略”作为第一个参数来区分并行版本和顺序版本。

struct by_row {};

struct Matrix3x3
{
    Matrix3x3(std::array<float,9> components) { ... }

    Matrix3x3(by_row,std::array<std::array<float,3>,3> rows) { ... }
};

呼叫看起来像:

    Matrix3x3 m{1,1,1};
    Matrix3x3 n{by_row{},{{{1,0},{0,1}}}};

question linked in one of the comments above 中解释了奇怪的额外大括号。)

(Godbolt)(其实我更喜欢this version。)