以均匀初始化的尾随逗号

Trailing comma in uniform initialization

本文关键字:初始化      更新时间:2023-10-16

当我在统一初始化期间使用尾逗号时,是否存在潜在的语义差异?

std::vector< std::size_t > v1{5, }; // allowed syntax
std::vector< std::size_t > v2{10};

我可以使用尾随逗号使编译器选择std::vector::vector(std::initializer_list< std::size_t >)构造函数,而不是std::vector::vector(std::size_t, const std::size_t &),或者是否还有其他技巧?

我可以使用它来检测是否存在 std::initializer_list -constructor过载?

考虑以下代码,必须选择哪个构造函数?

struct A { A(int) { ; } A(double, int = 3) { ; } };
A a{1};
A b{2, };

在两种情况下选择gcc 8A(int)都接受此代码。

首先,C 语法规则使 Braced-Init-list 的尾随,可选。引用dcl.init/1

声明器可以指定标识符的初始值 宣布。标识符指定一个正在初始化的变量。这 [dcl.init]其余部分中描述的初始化过程 也适用于其他句法上下文指定的初始化, 例如函数参数的初始化([expr.call])或 返回值的初始化([stmt.return])。

initializer:
  brace-or-equal-initializer
  ( expression-list )
brace-or-equal-initializer:
  = initializer-clause
  braced-init-list
initializer-clause:
  assignment-expression
  braced-init-list
braced-init-list:
  { initializer-list ,opt }
  { designated-initializer-list ,opt }
  { }

其次,您几乎不能超越过载分辨率系统。如果您使用此类语法并且可以使用此类std::initializer_list构造函数,它将始终使用std::initializer_list构造函数。

dcl.init.list/2:

如果第一个 参数为类型std :: initializer_list或引用 可能E的CV合格的std :: initializer_list用于某种类型E,并且 要么没有其他参数,否则所有其他参数都有 默认参数。 [注意:初始化列表构造函数比列表限制中的其他构造函数([over.match.list])....


下面的程序打印Using InitList

#include <iostream>
#include <initializer_list>
struct X{
    X(std::initializer_list<double>){ std::cout << "Using InitListn"; }
    X(int){ std::cout << "Using Single Arg ctorn"; }
};
int main(){
    X x{5};
}

尽管5int类型的字面意义,但选择单个参数构造函数应该是有意义的,因为它是完美的匹配。std::initializer_list<double>构造函数需要double的列表。但是,该规则有利于std::initializer_list<double>,因为它是 initiber-list-list构造函数

结果,即使下面的程序也因缩小转换而失败:

#include <iostream>
#include <initializer_list>
struct Y{
    Y(std::initializer_list<char>){ std::cout << "Y Using InitListn"; }
    Y(int, int=4){ std::cout << "Y Using Double Arg ctorn"; }
};
int main(){
    Y y1{4777};
    Y y2{577,};
    Y y3{57,7777};
}

响应您下面的评论:" ,如果与std :: prinistizer_list没有过多载荷,或者它不是第一个构造函数的参数?" - 然后,Overload分辨率不选择它。演示:

#include <iostream>
#include <initializer_list>
struct Y{
    Y(int, std::initializer_list<double>){ std::cout << "Y Using InitListn"; }
    Y(int, int=4){ std::cout << "Y Using Double Arg ctorn"; }
};
int main(){
    Y y1{4};
    Y y2{5,};
    Y y3{5,7};
}

打印:

Y Using Double Arg ctor
Y Using Double Arg ctor
Y Using Double Arg ctor

如果没有可用的 initializer-list构造函数,则 {initializer-list...,}初始化器几乎落在dcl.init/16的 direct初始化 16,其语义被涵盖由DCL.Init/16

的程序段落

no。该逗号是使预处理器宏观技巧在没有编译错误的情况下起作用的让步。这对您的数据类型或大小没有任何意义。