Vlad Markushin
Vlad Markushin

Reputation: 463

Struct constructor call is ambiguous

I have 2 constructors in struct 'matrix'.

matrix(const unsigned int m, const unsigned int n);
matrix(const std::vector<std::vector<double>> &elements);

When I call it like this

matrix mat({{1},{1}});

It throws error

call of overloaded ‘matrix(<brace-enclosed initializer list>)’ is ambiguous
note: candidate: matrix::matrix(const std::vector<std::vector<double> >&)
note: candidate: matrix::matrix(const matrix&)

So, it thinks, that {{1},{1}} - is 'matrix' object, but how?

Upvotes: 3

Views: 1261

Answers (2)

Useless
Useless

Reputation: 67802

So, it thinks, that {{1},{1}} - is 'matrix' object, but how?

In your sample code

matrix mat({{1},{1}});

you explicitly told the compiler to try and match that expression to a matrix constructor.

It doesn't "think" the expression {{1},{1}} is a matrix, it's trying to make it into one, because you asked it to.

As for why you get the error (which isn't what you asked, but seems worth mentioning), it's because

vector<double> v{1};

is a valid declaration of a vector with a single value (1.0), and so

vector<vector<double>> vv{{1},{1}};

is also a valid declaration of a vector containing two element vectors, each with a single double element of value 1.0, and so finally

mat{{{1},{1}}};

would be a valid match for the vector constructor. Since this conversion is allowed implicitly, we're allowed to rewrite

mat m({{1},{1}});

as

mat m(mat{{{1},{1}}});

and hence the ambiguity. Note the round and curly brackets carefully.

You can either make the constructor implicit, or just get used to uniform initialization style and write

mat m{{{1},{1}}};

in the first place.

Upvotes: 5

Vittorio Romeo
Vittorio Romeo

Reputation: 93344

When calling matrix mat({{1},{1}}) the compiler finds these two ambiguous construction paths:

  • Call the vector<vector>> constructor by constructing two vectors with one elements inside a vector.

  • Implicitly create a temporary matrix with the first constructor, then construct mat with that temporary.

    1. Create a temporary matrix from matrix(const unsigned int m, const unsigned int n). (The first {1} is matched to m, the second {1}is matched to n.)

    2. Try to construct mat from the temporary by using matrix(const matrix&).

Marking the first (or both) constructor(s) as explicit will unambiguously make matrix mat({{1},{1}}) invoke the...

matrix(const std::vector<std::vector<double>> &elements);

...one.

wandbox example

Upvotes: 3

Related Questions