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

M.M*_*M.M 7 c++ aggregate perfect-forwarding c++14

#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
}
Run Code Online (Sandbox Code Playgroud)

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

如果我使用std::forward(args)...而不是args...那么更多的错误出现; 如果我尝试使用{'a', 'b', 'c', '\0'}初始化程序而不是字符串文字,也会有错误.

有没有办法使这项工作,即允许X z{......};在大括号内的任何合法初始化器的内容x2被接受并实际上初始化x2

Col*_*mbo 5

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

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

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

  • Exploit brace elision - X也是一个聚合:

    struct X {
         X2 x2;
    } z{1, 2, "abc"}; // Ok
    
    Run Code Online (Sandbox Code Playgroud)
  • 声明buf具有类类型,例如std::string,或者在您的情况下可能更适合某些静态大小的等效类型(限制为10).