First, The C++ grammar rules makes the trailing , optional for braced-init-list. To quote dcl.init/1
A declarator can specify an initial value for the identifier being
declared. The identifier designates a variable being initialized. The
process of initialization described in the remainder of [dcl.init]
applies also to initializations specified by other syntactic contexts,
such as the initialization of function parameters ([expr.call]) or the
initialization of return values ([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 }
{ }
Secondly, you can't pretty much override the overload resolution system. It will always use the std::initializer_list constructor if you use such syntax and such std::initializer_list constructor is available.
dcl.init.list/2:
A constructor is an initializer-list constructor if its first
parameter is of type std::initializer_list or reference to
possibly cv-qualified std::initializer_list for some type E, and
either there are no other parameters or else all other parameters have
default arguments.
[ Note: Initializer-list constructors are favored over other constructors in list-initialization ([over.match.list])....
The program below prints Using InitList:
#include <iostream>
#include <initializer_list>
struct X{
X(std::initializer_list<double>){ std::cout << "Using InitList\n"; }
X(int){ std::cout << "Using Single Arg ctor\n"; }
};
int main(){
X x{5};
}
Despite the fact that 5 is a literal of type int, it should have made sense to select the single argument constructor since its a perfect match; and the std::initializer_list<double> constructor wants a list of double. However, the rules favour std::initializer_list<double> because its an initializer-list constructor.
As a result, even the program below fails because of narrowing conversion:
#include <iostream>
#include <initializer_list>
struct Y{
Y(std::initializer_list<char>){ std::cout << "Y Using InitList\n"; }
Y(int, int=4){ std::cout << "Y Using Double Arg ctor\n"; }
};
int main(){
Y y1{4777};
Y y2{577,};
Y y3{57,7777};
}
In response to your comment below, "what if there is no overloading with std::initializer_list, or it is not the first constructor's parameter?" - then overload resolution doesn't choose it. Demo:
#include <iostream>
#include <initializer_list>
struct Y{
Y(int, std::initializer_list<double>){ std::cout << "Y Using InitList\n"; }
Y(int, int=4){ std::cout << "Y Using Double Arg ctor\n"; }
};
int main(){
Y y1{4};
Y y2{5,};
Y y3{5,7};
}
Prints:
Y Using Double Arg ctor
Y Using Double Arg ctor
Y Using Double Arg ctor
If there is no initializer-list constructor available, then the {initializer-list...,} initializer pretty much falls back to direct initialization as per dcl.init/16, whose semantics are covered by the proceeding paragraph of dcl.init/16
std::initializer_list-constructor) is always selected. wandbox.org/permlink/Yy6VtcK5ISCbzZJp - songyuanyaov2{...}to call any constructor but the one takingstd::initializer_list....onlyv2(...)will callstd::vector::vector(std::size_t...)- jpo38