std::initializer_list type deduction
Asked Answered
S

1

8

Recently I wrote a very simple class.

class C
{
public:
    void AddString(std::initializer_list<std::pair<const char*,int>> x)
    {
          //irrelevant
    }
};

int main()
 {
           C c;
           c.AddString({ {"1",1}, {"2", 2}, {"3", 3} });
           .... //other unimportant stuff
           return 0;
 }

To my pleasant surprise it compiled and worked correctly. Can someone please explain to me how the compiler was able to deduce the nested braced initializers were for a std::pair? I am using MSVS 2013.

Shala answered 21/5, 2015 at 0:2 Comment(0)
K
9
c.AddString({ {"1",1}, {"2", 2}, {"3", 3} });

You're passing a braced-init-list, which itself contains nested brace-init-lists to AddString. The argument can match the std::initializer_list<std::pair<const char*,int>> parameter if the inner braced-init-lists can be converted to std::pair<const char*,int>.

This process of overload resolution occurs in two steps; first an attempt is made to match constructors of std::pair that take an std::initializer_list argument. Since std::pair has no such constructor, the second step occurs, where the other constructors of std::pair<const char*,int> are enumerated with char const[2] and int as the arguments. This will match the following pair constructor because char const[2] is implicitly convertible to char const * and the constructor itself is not explicit.

template< class U1, class U2 >
constexpr pair( U1&& x, U2&& y );

Quoting N3337 §13.3.1.7/1 [over.match.list]

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 an explicit constructor is chosen, the initialization is ill-formed.

Kerbela answered 21/5, 2015 at 0:37 Comment(3)
Great answer, much more complete!Anticlerical
Thank you, that clarifies some things..I need to understand a little bit more about over load resolution when braced init lists are involved.Shala
@Shala The rules for overload resolution when list-initialization is involved are what I copy-pasted above. If you meant you need to get familiar with overload resolution in general, I suggest you start with this video (watch the whole series if you can find the time).Kerbela

© 2022 - 2024 — McMap. All rights reserved.