Like @Eljay said, Nicolai Josuttis covers this thoroughly in "The Nightmare of Initialization in C++.
Usually curly braces initialization does the right thing. It prevents the most vexing parse and narrowing conversions.
For your example, this would be
A c{1,2.0};
The main problem that comes to mind is when it's ambiguous if you wanted the initializer list constructor or the n-argument constructor:
std::vector<std::size_t> x{100, 30};
std::vector<std::size_t> y(100, 30);
What is x.size()? y.size()? I believe x.size()==2 and y.size()==100.
In this situation, personally, I would write a helper function to construct the vector of n copies of the same element so I don't have to think about the subtle difference between these:
temmplate<class T>
auto vector_of_n_copies(std::size_t n, T) {
auto const v = std::vector<T>(n,T);
assert(v.size()==n);
return v;
}
Additionally, you should initialize in the constructor via member initialization like this:
class A{
int x;
float y;
public:
A(int xa, float ya): x{xa}, y{ya} {}
};
From C++ Core Guidelines, C.49: Prefer initialization to assignment in constructors,
Reason An initialization explicitly states that initialization, rather than assignment, is done and can be more elegant and efficient. Prevents “use before set” errors.