当目标与数组聚合时,完美转发失败

Perfect forwarding fails when target is aggregate with array

本文关键字:完美 转发 失败 目标 数组      更新时间:2023-10-16
#include <iostream>
struct X2
{
    int i;
    int j;
    char buf[10];
};
X2 glob{1,2,"abc"};    // OK
struct X
{
     X2 x2;
     template<typename... Args>
     X(Args&&... args): x2{args...} {}
};
int main()
{
     X x;                // OK
     X y{1, 2};          // OK
     X z{1, 2, "abc"};   // error
}

最后一行给出错误:17 : error: invalid conversion from 'const char*' to 'char' [-fpermissive]

如果我使用 std::forward(args)... 而不是 args...那么会出现更多错误;如果我尝试使用 {'a', 'b', 'c', ''} 作为初始值设定项而不是字符串文字,也会出错。

有没有办法使这项工作,即允许X z{......};接受大括号内的任何内容,这些内容将成为x2的法定初始值设定项,并且实际上确实初始化了x2

这是一个从 C++98 继承而来的不稳定的设计问题:某些转换或初始化在语法上仅限于文字,特别是字符串文字作为字符数组的初始值设定项 ([dcl.init.string]/1( 和整数文字作为空指针常量 ([conv.ptr]/1(。当然,这与"完美"转发并不相符。

对于空指针,通过引入 nullptr 来规避该问题,可以使用它代替0,即使在转发后也能正常工作。

在您的情况下,基本上有两个主要选项:

  • 利用大括号省略 - X也是一个聚合:

    struct X {
         X2 x2;
    } z{1, 2, "abc"}; // Ok
    
  • 声明buf具有类类型,例如 std::string,或者,也许更适合您的情况,一些静态大小的等效项(限制为大小 10(。