如何避免重新键入类型信息以进行聚合初始化?

dar*_*une 4 c++ language-lawyer aggregate-initialization constexpr c++17

我有以下示例:

#include <array>

struct A {
    const char* str;
    const char* str2;
};

template<size_t N>
struct As {
    std::array<A,N> elems_;
};


template<class... Args>
As(Args...)->As<sizeof...(Args)>; //<-- NOTE: deduction guide !


constexpr static As as{A{"a","b"}, A{"1","2"}};//<-- 'retyping' A here


int main() {
  return as.elems_.size(); 
}
Run Code Online (Sandbox Code Playgroud)

链接到非工作示例

尽管此代码有效,但我想避免在A汇总列表中对的“重新键入” ,但是如果不加说明,则推导指南将失败:("cannot deduce template arguments for 'As'"我想这很有意义)。解决此问题的一种方法可能是通过手写我需要的任意数量的扣除指南,此后我可以A在每个扣除指南中编写类型(即:针对我需要的每种尺寸的容器进行一次扣除)。

Max*_*hof 5

嵌套聚合初始化具有或多或少令人惊讶的行为,您无需添加嵌套{/ }即可匹配。

例如,是您初始化的方式std::array<std::array<int, 2>, 2>

std::array<std::array<int, 2>, 2> arr = { 1, 1, 2, 2 };
Run Code Online (Sandbox Code Playgroud)

这样做{ {1, 1}, {2, 2} }没有工作!

同样,在您的情况下,聚合初始化将不需要嵌套的{/ }已经完成了CTAD(好,给定的模板参数):

constexpr static As<2> as{"a","b", "1","2"}; // Ok!
Run Code Online (Sandbox Code Playgroud)

知道了这一点,我们可以添加以下推导指南:

template<class ... Ts>
As(Ts...) -> As<(sizeof...(Ts) + 1)/2>;
Run Code Online (Sandbox Code Playgroud)

这选择N为“一半参数”。实际上,现在您可以像这样初始化:

constexpr static As as{"a","b", "1","2"}; // Deduces N = 2.
Run Code Online (Sandbox Code Playgroud)

演示:https : //godbolt.org/z/oznEwl

是的,为了获得更好的可读性,这失去了使用{/ 构造输入的能力},但我将此归咎于聚合初始化(请参见上面的嵌套数组示例)。

  • *执行{{{1,1},{2,2}}`是行不通的!*这是因为您尚未将其完全扩展为应有的功能。使用`{{{1,1},{2,2}}}`是有效的,因为外部花括号创建了数组,内部花括号创建了外部数组的初始化程序列表,内部花括号是每个元素。您还可以全力以赴并使用`{{{{{1,1}},{{2,2}}}};`进行专门的研究。 (4认同)