问题
class A
{
int value_;
public:
A(int value):value_(value){}
};
A get_a1(int value)
{
return A(value);
}
A get_a2(int value)
{
return {value};
}
int main()
{
A a1 = get_a1(1);
A a2 = get_a2(2);
}
What is the difference between get_a1()
and get_a2()
, if any ?
How is return {value};
called ? (I guess "calling constructors via curly braces" is not the proper way to refers to this)
回答1:
In your case, there is simply no difference. But if you modify your code a bit, there will be a visible difference!
First of all, you can construct your type in different ways, all described here: initilization
The difference come in, if your class provides also a constructor which takes a std::initializer_list
.
See the following code modified/extended to show the difference:
class A
{
public:
A(int value):value_(value){ std::cout << "int" << std::endl;}
A(const std::initializer_list<int>& ){ std::cout << "list" << std::endl;}
void print()
{
std::cout << value_ << std::endl;
}
private:
int value_;
};
A get_a1(int value)
{
std::cout << "()" << std::endl;
return A(value);
}
A get_a2(int value)
{
std::cout << "{}" << std::endl;
return {value};
}
int main()
{
A a1 = get_a1(1);
a1.print();
A a2 = get_a2(2);
a2.print();
}
If you run that prog, you will see that using {}
will call the constructor with std::initializer_list
and using ()
will use your int
constructor.
Why is described here in the standard:
§13.3.1.7 [over.match.list]/p1:
When objects of non-aggregate class type
T
are list-initialized (8.5.4), overload resolution selects the constructor in two phases:
- Initially, the candidate functions are the initializer-list constructors (8.5.4) of the class
T
and the argument list consists of the initializer list as a single argument.- If no viable initializer-list constructor is found, overload resolution is performed again, where the candidate functions are all the constructors of the class
T
and the argument list consists of the elements of the initializer list.If the initializer list has no elements and
T
has a default constructor, the first phase is omitted. In copy-list-initialization, if anexplicit
constructor is chosen, the initialization is ill-formed.
In addition, initializer list constructors do not allow narrowing!
§8.5.4 List-initialization
(3.4) Otherwise, if T is a class type, constructors are considered. The applicable constructors are enumerated and the best one is chosen through overload resolution ([over.match], [over.match.list]). If a narrowing conversion (see below) is required to convert any of the arguments, the program is ill-formed.
来源:https://stackoverflow.com/questions/60195765/c-calling-constructors-via-curly-braces