4

我想为 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>, 3> rows) { }
};

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

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

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

Matrix3x3{ {{1.f, 2.f, 3.f, 4.f, 5.f, 6.f, 7.f, 8.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”是完整的初始化,所有其他的都是大括号省略的。这就是造成歧义的原因。

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

4

2 回答 2

1

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

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, 2.f, 3.f };
std::array<float, 3> row2{ 4.f, 5.f, 6.f };
std::array<float, 3> row3{ 7.f, 8.f, 9.f };

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

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

于 2021-02-20T22:19:11.630 回答
1

使用标签:空结构,例如struct by_row{};. 然后你的 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,0,0,0,1,0,0,0,1};
    Matrix3x3 n{by_row{}, {{{1,0,0},{0,1,0},{0,0,1}}}};

(在上述评论之一中链接的问题中解释了奇怪的额外大括号。)

( Godbolt ) (其实我更喜欢这个版本。)

于 2021-02-20T22:54:30.330 回答