Nested list (vector of vectors of strings) initialization fails

  • A+
Category:Languages

This code:

#include <vector> #include <string> #include <iostream>  class MyClass { public:   MyClass(const std::vector<std::vector<std::string>> & v)   {     std::cout << "Vector of string vectors size: " << v.size() << "/n";      for (size_t i = 0; i < v.size(); i++)       std::cout << "Vector #" << i << " has size " << v[i].size() << "/n";   } };  int main() {   MyClass({ { "a" } }); // <--- ok   MyClass({ { "a", "b" } }); // <--- PROBLEM   MyClass({ { std::string("a"), "b" } }); // <--- ok   MyClass({ { "a", "b", "c" } }); // <--- ok   MyClass({ { "a" },{ "c" } }); // <--- ok   MyClass({ { "a", "b" },{ "c", "d" } }); // <--- ok } 

outputs this (Visual Studio 2017):

Vector of string vectors size: 1 Vector #0 has size 1 Vector of string vectors size: 4 Vector #0 has size 97 Vector #1 has size 0 Vector #2 has size 0 Vector #3 has size 0 Vector of string vectors size: 1 Vector #0 has size 2 Vector of string vectors size: 1 Vector #0 has size 3 Vector of string vectors size: 2 Vector #0 has size 1 Vector #1 has size 1 Vector of string vectors size: 2 Vector #0 has size 2 Vector #1 has size 2 

So, it works OK in all cases except in the case where we have a vector of one vector, containing two strings. It also works in the above case if we explicitly construct std::string from one of the string literals. If both are just plain string literals, the compiler seems to get "confused" and constructs a vector of 4 items, the first of which contains 97 strings. Note that 97 is the character code of "a".

I guess my question is, should the compiler interpret this problematic construction as I'd expect, or is this bad code to initialize a nested list like this?


The inner vector in MyClass({ { "a", "b" } }) is creating using range constructor:

template <class InputIterator>   vector (InputIterator first, InputIterator last, const allocator_type& alloc = allocator_type()); 

This happens because { "a", "b" } is interpreted not as std::initializer_list<std::string> but as a pair of raw pointers.

Comment

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: