Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does {} as function argument not lead to ambiguity?

Tags:

Consider this code:

#include <vector>
#include <iostream>

enum class A
{
  X, Y
};

struct Test
{
  Test(const std::vector<double>&, const std::vector<int>& = {}, A = A::X)
  { std::cout << "vector overload" << std::endl; }

  Test(const std::vector<double>&, int, A = A::X)
  { std::cout << "int overload" << std::endl; }
};

int main()
{
  std::vector<double> v;
  Test t1(v);
  Test t2(v, {}, A::X);
}

https://godbolt.org/z/Gc_w8i

This prints:

vector overload
int overload

Why does this not produce a compilation error due to ambiguous overload resolution? If the second constructor is removed, we get vector overload two times. How/by what metric is int an unambiguously better match for {} than std::vector<int>?

The constructor signature can surely be trimmed further, but I just got tricked by an equivalent piece of code and want to make sure nothing important is lost for this question.

like image 269
Max Langhof Avatar asked Mar 03 '20 14:03

Max Langhof


1 Answers

It's in [over.ics.list], emphasis mine

6 Otherwise, if the parameter is a non-aggregate class X and overload resolution per [over.match.list] chooses a single best constructor C of X to perform the initialization of an object of type X from the argument initializer list:

  • If C is not an initializer-list constructor and the initializer list has a single element of type cv U, where U is X or a class derived from X, the implicit conversion sequence has Exact Match rank if U is X, or Conversion rank if U is derived from X.

  • Otherwise, the implicit conversion sequence is a user-defined conversion sequence with the second standard conversion sequence an identity conversion.

9 Otherwise, if the parameter type is not a class:

  • [...]

  • if the initializer list has no elements, the implicit conversion sequence is the identity conversion. [ Example:

    void f(int);
    f( { } ); // OK: identity conversion
    

    end example ]

The std::vector is initialized by constructor and the bullet in bold deems it a user defined converison. Meanwhile, for an int, this is the identity conversion, so it trumps the rank of the first c'tor.

like image 102
StoryTeller - Unslander Monica Avatar answered Sep 21 '22 17:09

StoryTeller - Unslander Monica