Strange behavior of std::initializer_list of std::strings
It calls
string(const char* b, const char* e)
string ctor overload.
It works only if b
and e
points to the same string literal. Otherwise it is undefined behaviour.
For starters there is no used the constructor that accepts an initializer list because such a constructor looks like
basic_string(initializer_list<charT>, const Allocator& = Allocator());
^^^^^
So the compiler searches another appropriate constructor and it finds such a constructor. It is the constructor
template<class InputIterator>
basic_string(InputIterator begin, InputIterator end, const Allocator& a = Allocator());
That is the expressions "one"
and "two"
are considered as iterators of the type const char *
.
So the function test
has undefined behavior.
You could write for example (provided that string literals with the same content are stored as one string literal in memory, which is not guaranteed and depends on the selected compiler options).
#include <iostream>
#include <string>
void test(const std::string &value) { std::cout << "string overload: " << value << std::endl; }
//void test(const std::vector<std::string> &) { std::cout << "vector overload" << std::endl; }
int main()
{
test({ "one", "one" + 3 });
}
And you will get a valid result.
string overload: one
Pay attention to that this construction
{ "one", "two" }
is not an object of the type std::initializer_list<T>
. This construction does not have a type. It is a braced-init-list
that is used as an initialzer. Simply the compiler tries at first to use a constructor that have the first parameter of the type std::initializer_list to use with this initializer.
For example if you will use the class std::vector<const char *>
then indeed the compiler will use its constructor with std::initializer_list and correspondingly initializes its parameter with this braced-init-list. For example
#include <iostream>
#include <vector>
int main()
{
std::vector<const char *> v( { "one", "two" } );
for ( const auto &s : v ) std::cout << s << ' ';
std::cout << '\n';
}