0

If I write this

std::vector<std::string> v{"one","two","three"};

What is the type inferred to the associated std::initializer_list template ? In other words, when the char * string literals are converted to std::string ?

It's a better idea to declare it as

std::vector<std::string> v{std::string("one"),
                           std::string("two"),
                           std::string("three")};

to avoid issues connected to the type-deduction mechanism of the templates involved ? I'll keep the same optimizations with this ?

7
  • What problem are you trying to solve? Commented Mar 28, 2014 at 13:59
  • @LightnessRacesinOrbit nothing in particular, I'm trying to understand how the C++ typing system works in this particular case. Commented Mar 28, 2014 at 14:00
  • Okay. I warn you, that's a dangerous path to go down ;) Commented Mar 28, 2014 at 14:01
  • @LightnessRacesinOrbit I would like you to elaborate on that Commented Mar 28, 2014 at 14:04
  • C++'s rules for this sort of thing can be very complex. Commented Mar 28, 2014 at 14:07

3 Answers 3

7

Update: To answer your question about type inference: The initializer list constructor of vector<string> takes an initializer_list<string>. It is not templated, so nothing happens in terms of type inference.

Still, the type conversion and overload resolution rules applied here are of some interest, so I'll let my initial answer stand, since you have accepted it already:

Original answer:

At first, the compiler only sees the initializer list {"one","two","three"}, which is only a list of initializers, not yet an object of the type std::initializer_list.

Then it tries to find an appropiate constructor of vector<string> to match that list. How it does that is a somewhat complicated process you would do best to look up in the standard itself if you are interested in the exact process.

Therefore, the compiler decides to create an actual object of std::initializer_list<string> from the initializer list, since the implicit conversion from the char*'s to std::strings makes that possible.

Another, maybe more interesting example:

std::vector<long>   vl1{3};
std::vector<string> vs1{3};
std::vector<string> vs2{0};

What do these do?

  1. The first line is relatively easy. The initializer list {3} can be converted into a std::initializer_list<long> analogous to the {"onm", "two", "three"} example above, so you get a vector with a single element, which has value 3.

  2. The second line is different. It constructs a vector of 3 empty strings. Why? Because an initializer list {3} can by no means be converted into an std::initializer_list<string>, so the "normal" constructor std::vector<T>::vector(size_t, T = T()) kicks in and gives three default-constructed strings.

  3. Well this one should be roughly the same as the second, right? It should give an empty vector, in other words, with zero default-constructed strings. WRONG!. The 0 can be treated as a nullpointer constant, and validates the std::initializer_list<string>. Only this time the single string in that list gets constructed by a nullpointer, which is not allowed, so you get an exception.

Sign up to request clarification or add additional context in comments.

7 Comments

I'm not really satisfied by this answer, the fact that std::vector and std::initializer_list are taking the same T justifies the fact that "one" is a valid input because one of the constructors of std::string takes a char *. Doesn't really explain how type inference works and what kind of optimizations C++11 is allowed to make.
@user2485710 If that's your question, then your example was unrelated. Also, that question would not be a good fit for SO, because it's overly broad.
@user2485710 I have tried to explain a bit more what happens - and let a crucial, interesting part out. Beause it's overly tedious and interesting only for language lawyers ;-)
Frankly even for some language lawyers, i.e. me, it's still singularly uninteresting. ;)
the reason why I used std::string and char * in my example is that this special case implies a conversion between types, especially between a pointer and a C++ object . Type inference in C++11, as far as I experimented, doesn't really play nice with pointers, for example auto reveals some weaknesses when using pointers. Here we have some room for optimization ( which means that C++ needs to cut somewhere, somehow ) and 2 types representing the same "thing" that the user wants to build.
|
3

There is no type inference because vector provide only a fully specialized constructor with the initializer list. We could add a template indirection to play with type deduction. The example below show that a std::initializer_list<const char*> is an invalid argument to the vector constructor.

#include <string>
#include <vector>

std::string operator"" _s( const char* s, size_t sz ) { return {s, s+sz}; }

template<typename T>
std::vector<std::string> make_vector( std::initializer_list<T> il ) {
    return {il};
}

int main() {
    auto compile = make_vector<std::string>( { "uie","uieui","ueueuieuie" } ); 
    auto compile_too = make_vector<std::string>( { "uie"_s, "uieui", "ueueuieuie" } ); 
    //auto do_not_compile = make_vector( { "uie","uieui","ueueuieuie" } ); 
}

Live demo

Comments

2

From http://en.cppreference.com/w/cpp/language/string_literal:

The type of an unprefixed string literal is const char[]

Thus things go this way:

#include <iostream>
#include <initializer_list>
#include <vector>
#include <typeinfo>
#include <type_traits>
using namespace std;

int main() {
    std::cout << std::boolalpha;
    std::initializer_list<char*> v = {"one","two","three"}; // Takes string literal pointers (char*)
    auto var = v.begin();
    char *myvar;
    cout << (typeid(decltype(*var)) == typeid(decltype(myvar))); // true

    std::string ea = "hello";
    std::initializer_list<std::string> v2 = {"one","two","three"}; // Constructs 3 std::string objects
    auto var2 = v2.begin();
    cout << (typeid(decltype(*var2)) == typeid(decltype(ea))); // true
    std::vector<std::string> vec(v2);
    return 0;
}

http://ideone.com/UJ4a0i

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.