initializer_list deduction

Hi all,

Is it this behavior correct ?

//Code ----------------------
#include <initializer_list>
#include
#include
#include

using namespace std;

void foo( initializer_list<typename vector::value_type> list )
{
for (auto& item : list)
{
cout << item << endl;
}
}

int main( /* int argc, char* argv */ )
{
foo( { {“k0”, “v0”}, {“k1”, “v1”} } );
return 0;
}

//End code ----------------------

$ clang++ --version
clang version 3.1 (trunk 155038)
Target: i386-pc-linux-gnu
Thread model: posix

$ clang++ -std=c++11 initializer_list_test.cpp
$ ./a.out
k0
k1

I believe you're calling the std::string(Iterator begin, Iterator end)
constructor. As you could with this code:

std::string s{"k0", "v0"};

(or even C++03 code: std::string s("k0", "v0"); )

You probably got luck with the string constant layout & ran into "v0"
from "k0" - but I suspect the length of your strings is 3, not 2
(including the null character between "v0" and "k0")

Hi all,

Is it this behavior correct ?

//Code ----------------------
#include <initializer_list>
#include
#include
#include

using namespace std;

void foo( initializer_list<typename vector::value_type> list )
{
for (auto& item : list)
{
cout << item << endl;
}
}

int main( /* int argc, char* argv */ )
{
foo( { {“k0”, “v0”}, {“k1”, “v1”} } );
return 0;
}

//End code ----------------------

$ clang++ --version
clang version 3.1 (trunk 155038)
Target: i386-pc-linux-gnu
Thread model: posix

$ clang++ -std=c++11 initializer_list_test.cpp
$ ./a.out
k0
k1


I would have expected that the initializer_list be deduced to something like
an associative container (a compile time error).

I believe you’re calling the std::string(Iterator begin, Iterator end)
constructor. As you could with this code:

std::string s{“k0”, “v0”};

(or even C++03 code: std::string s(“k0”, “v0”); )

Oh, you’re right!

You probably got luck with the string constant layout & ran into “v0”
from “k0” - but I suspect the length of your strings is 3, not 2
(including the null character between “v0” and “k0”)

But… I’m concerned about the ambiguous resolution in this case …

//Code ----------------------
#include <initializer_list>
#include
#include
#include
#include

using namespace std;

void foo( initializer_list<typename vector::value_type> list )
{
for (auto& item : list)
{
cout << item << endl;
}
}

void foo( initializer_list<typename map<string, string>::value_type> list )
{
for (auto& item : list)
{
cout << item.first << endl;
}
}

int main( /* int argc, char* argv */ )
{
foo( { {“k0”, “v0”}, {“k1”, “v1”} } );
return 0;
}

//End code ----------------------

It seems that no solution.

Regards,
Fernando.

Are you concerned that Clang has implemented the resolution
incorrectly? or that the standard has specified it incorrectly?

The same ambiguity exists without initializer_lists, though:

void foo(std::string);
void foo(std::pair<std::string, std::string>);

foo({"k0", "v0"});

Hi all,

Is it this behavior correct ?

//Code ----------------------
#include <initializer_list>
#include
#include
#include

using namespace std;

void foo( initializer_list<typename vector::value_type> list )
{
for (auto& item : list)
{
cout << item << endl;
}
}

int main( /* int argc, char* argv */ )
{
foo( { {“k0”, “v0”}, {“k1”, “v1”} } );
return 0;
}

//End code ----------------------

$ clang++ --version
clang version 3.1 (trunk 155038)
Target: i386-pc-linux-gnu
Thread model: posix

$ clang++ -std=c++11 initializer_list_test.cpp
$ ./a.out
k0
k1


I would have expected that the initializer_list be deduced to something
like
an associative container (a compile time error).

I believe you’re calling the std::string(Iterator begin, Iterator end)
constructor. As you could with this code:

std::string s{“k0”, “v0”};

(or even C++03 code: std::string s(“k0”, “v0”); )

Oh, you’re right!

You probably got luck with the string constant layout & ran into “v0”
from “k0” - but I suspect the length of your strings is 3, not 2
(including the null character between “v0” and “k0”)

But… I’m concerned about the ambiguous resolution in this case …

//Code ----------------------
#include <initializer_list>
#include
#include
#include
#include

using namespace std;

void foo( initializer_list<typename vector::value_type> list )
{
for (auto& item : list)
{
cout << item << endl;
}
}

void foo( initializer_list<typename map<string, string>::value_type> list )
{
for (auto& item : list)
{
cout << item.first << endl;
}
}

int main( /* int argc, char* argv */ )
{
foo( { {“k0”, “v0”}, {“k1”, “v1”} } );
return 0;
}

//End code ----------------------

It seems that no solution.

Are you concerned that Clang has implemented the resolution
incorrectly? or that the standard has specified it incorrectly?

I’m not really worried about either.
I want to write something like this in C++

my_type variables = {
{“var” , “value”}
, {“hello” , “Hello World!”}
, {“empty” , “”}
, {“path” , “/foo/bar”}
, {“x” , “1024”}
, {“y” , “768”}
, {“list” , { “val1”, “val2”, “val3” }}
, {“keys” , { {“key1”, “val1”}, { “key2” “val2”} } }
};

Is like a sum type (variant).

The same ambiguity exists without initializer_lists, though:

void foo(std::string);
void foo(std::pair<std::string, std::string>);

foo({“k0”, “v0”});

The most simple and short way I found to avoid the ambiguity was as follows …

#include <initializer_list>

#include
#include
#include
#include

using namespace std;

void foo( initializer_list<typename vector::value_type> list )
{
for (auto& item : list)
{
cout << item << endl;
}
}

void foo( initializer_list<typename map<string, string>::value_type> list )
{
cout << “map!!”;
for (auto& item : list)
{
cout << item.first << endl;
}
}

string operator"" _s (const char* p, size_t n)
{
return string(p,n);
}

int main( /* int argc, char* argv */ )
{
foo( { {“k0”_s, “v0”}, {“k1”, “v1”} } );
foo( {“a”, “b”} );

return 0;
}

I think not so bad.

Thanks and regards,
Fernando.