pedim pedim - 1 year ago 65
C++ Question

How to distinguish two overloaded functions with arguments of non-nested and nested initializer_list?

Suppose I have a Matrix class and I'd like to initialize my Matrix objects in two ways:

Matrix a = {1,2,3} // for a row vector


Matrix b = {{1,2,3},{4,5,6},{7,8,9}} // for a matrix

As a result, I implemented two copy constructors as below

class Matrix {
size_t rows, cols;
double* mat;
Matrix() {}
Matrix(initializer_list<double> row_vector) { ... }
Matrix(initializer_list< initializer_list<double> > matrix) { ... }

No matter how I change my interface, such as adding an
keyword or change the nested version to
Matrix(initializer_list< vector<double> > matrix)
. It will always cause ambiguities between these two cases:

Matrix a = {1,2,3};n
Matrix b = {{1}, {2}, {3}};

I'm not quite familiar with the stuff like direct/copy initialization or implicit type conversion. Are there any solutions for this problem?

Answer Source

There is no solution which will unambiguously work in every case. However, you can create ways to disambiguate cases:

template<typename T>
auto il(std::initializer_list<T> the_il) -> std::initializer_list<T> { return the_il; }

Matrix b = {il({1}), {2}, {3}};

However, I would personally suggest that you be explicit about it. If a user wants a matrix containing one row, then it should look like a matrix containing one row, not like a vector:

Matrix a = {{1,2,3}};

So I would suggest ditching the first overload altogether.

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download