c++ - 如何避免为聚合初始化重新输入类型信息?

标签 c++ language-lawyer c++17 constexpr aggregate-initialization

我有以下示例:

#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(); 
}

Link to non-working example

虽然此代码有效,但我想避免在聚合列表中“重新输入”A,但如果我将其遗漏,推导指南将失败:“cannot推导出 'As'" 的模板参数(我想这是有道理的)。也许解决这个问题的一种方法是手写我需要的任何数量的推导指南,从那时起我可以在每个推导指南中编写 A 类型(即:我需要的每个尺寸一个推导容器)。

最佳答案

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

例如,this是你如何初始化 std::array<std::array<int, 2>, 2> :

std::array<std::array<int, 2>, 2> arr = { 1, 1, 2, 2 };

正在做 { {1, 1}, {2, 2} }not工作!

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

constexpr static As<2> as{"a","b", "1","2"}; // Ok!

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

template<class ... Ts>
As(Ts...) -> As<(sizeof...(Ts) + 1)/2>;

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

constexpr static As as{"a","b", "1","2"}; // Deduces N = 2.

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

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

关于c++ - 如何避免为聚合初始化重新输入类型信息?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56236713/

相关文章:

c++ - 像复制一样在STL中转换数组

c++ - 指向 std::invoke 中成员函数对象的指针

c++ - 使用折叠表达式构造平凡对象

c++ - union 中的标量成员是否计入公共(public)初始序列?

c++ - 为什么 void{} 不存在?

c++ - 错误的输出(继承)

c++ - 如何在特定位置使用 switch 或 if-else 步骤将十六进制值分配给数组?

c++ - Java中非常简单的C++词法分析

c++ - 为什么标准区分直接列表初始化和复制列表初始化?

c++ - 具有虚拟析构函数的池分配器