#include <iostream>
#include <string>
#include <typeinfo>
#include <typeindex>
#include <map>
#include <vector>
class Base{
public:
virtual ~Base() {}
};
class Derived: public Base { };
int main(){
int arr[10];
Derived d;
Base *p = &d;
std::map<std::type_index, std::string> proper_name = {
{typeid(int), "int"}, {typeid(double), "double"}, {typeid(float), "float"}, {typeid(char), "char"},
{typeid(Base), "Base"}, {typeid(Derived), "Derived"}, {typeid(std::string), "String"},
{typeid(int[10]), "Ten int Array"}, {typeid(p), "Base Pointer"}};
}
I'm trying to make sense of the implicit conversions that occur in this list-initialization. From 13.3.1.7 of N3337:
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.
8.5.4:
A constructor is an initializer-list constructor if its first parameter is of type
std::initializer_list<E>or reference to possibly cv-qualifiedstd::initializer_list<E>for some typeE, and either there are no other parameters or else all other parameters have default arguments
So the following list of constructors for std::map indicates
map (initializer_list<value_type> il,
const key_compare& comp = key_compare(),
const allocator_type& alloc = allocator_type());
is the candidate function, value_type in this case is pair<const type_index, std::string>. Lastly from 13.3.3.1.5:
If the parameter type is
std::initializer_list<X>or “array ofX”135 and all the elements of the initializer list can be implicitly converted toX, the implicit conversion sequence is the worst conversion necessary to convert an element of the list toX.
So it is a valid conversion as long as the elements of the braced-list implicitly convert to pair<const type_index, std::string>. But those elements are also braced-lists themselves. Pair does not take an initializer-list constructor, from here it seems that copy-initialization from a braced-init list uses the second part of 13.3.1.7 to construct the object. So the following:
pair<const type_index, std::string> p = {typeid(int), "int"}
becomes:
pair<const type_index, std::string> p(typeid(int), "int")
but is this considered an implicit conversion? How can use of a two-argument constructor be considered an implicit conversion? What are the standard's comments on this?