关于C#:当目标与数组聚合时,完美转发失败

Perfect forwarding fails when target is aggregate with array

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#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', '\\0'}作为初始化程序而不是字符串文字,也会出现错误。

是否有一种方法可以使这项工作正常进行,即允许X z{......};接受括号内的任何东西,这些东西将成为x2的合法初始值设定项,并且实际上会初始化x2


这是一个从C 98继承的不稳定的设计问题:某些转换或初始化在语法上仅限于文字,尤其是作为字符串数组的初始化程序的字符串文字([dcl.init.string] / 1)和整数文字,例如空指针常量([conv.ptr] / 1)。当然,这与"完美"转发并不能很好地配合。

对于空指针,通过引入nullptr可以解决此问题,可以使用nullptr代替0,并且即使转发后也可以正常工作。

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

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

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