pair vs tuple in uniform initialization
I'm having some problems coping with this "uniform initialization"/"initialization list" example from Bjarne Stroustrup himself.
What bothers me is that the example does not work with tuples:
Code:
#include <string>
#include <list>
#include <tuple>
#include <utility>
//This works: Uniform initialization, normal
std::pair<std::string, std::string> a{"Nygaard","Simula"};
std::tuple<std::string, std::string> b{"Richards","BCPL"};
//This doesn't work, initialization lists, normal
//std::pair<std::string, std::string> aa{{"Nygaard","Simula"}};
//std::tuple<std::string, std::string> bb{{"Richards","BCPL"}};
//This works
std::list<std::pair<std::string, std::string>> languages_pair = {
{"Nygaard","Simula"}, {"Richards","BCPL"}, {"Ritchie","C"}
};
//but this doesn't
std::list<std::tuple<std::string, std::string>> languages_tuple = {
{"Nygaard","Simula"}, {"Richards","BCPL"}, {"Ritchie","C"}
};
int main()
{ }
I can't understand why the tuple example is not working :/
Which constructor are the pairs using that the tuple doesn't have?
Re: pair vs tuple in uniform initialization
Hi,
the constructor tuple::tuple(P1, P2, ...PN) is explicit.
Code:
std::tuple<std::string, std::string> b{"Richards","BCPL"};
Here you are explicitly calling the constructor.
Code:
std::list<std::tuple<std::string, std::string>> languages_tuple = {
{"Nygaard","Simula"}, {"Richards","BCPL"}, {"Ritchie","C"}
};
Here you are trying to implicitly call the constructor which is not allowed.
As opposed to that, std::pair::pair(const Type1& __Val1, const Type2& __Val2); is not explicit.
Re: pair vs tuple in uniform initialization
adding to treuss post, note that as in c++03 there are direct and copy intializations, in c++11 there are also direct and copy list-initializations. That is, an initialization of the form "= { ... }" requires copy-initialization semantics for all the set of braces recursively and not just the outermost one. So, in the code
Code:
std::list<std::tuple<std::string, std::string>> languages_tuple = { {"Nygaard","Simula"}, {"Richards","BCPL"}, {"Ritchie","C"} };
the outermost braces match to list::list(initializer_list<tuple<string,string>>), and the innermost braces sets would match to a non-explicit ( because of the copy-list-initialization ) converting tuple<string,string>(?) constructor that does not exist, hence the error.
Maybe, your question stemmed from you trying to recover the initialization mechanism through the std::list ctor only; note that from the list pov the initialization is "legal", as in the c++03 code:
Code:
#include <vector>
std::vector<int> v1;
std::vector<std::vector<int>> v2(v1.begin(),v1.end()); // invokes an explicit ctor
so there would be no problem to initialize the list through an explicit converting costructor of tuple because the list initializer list ctor is equivalent to the iterator range ctor in the obvious way; the expected behavior is enforced by an ad hoc rule triggered by the copy-initialization context.
For example, the following nearly equivalent code should ( see below ) compile
Code:
std::initializer_list<std::tuple<std::string, std::string>> il{
{"Nygaard","Simula"}, {"Richards","BCPL"}, {"Ritchie","C"}
};
std::list<std::tuple<std::string, std::string>> languages_tuple = il;
unfortunately, I've no initializer list supporting compiler at my disposal :(, so, I'll leave it as a conjecture ...
Re: pair vs tuple in uniform initialization
Hum... explicit multi-variable constructors...
Thanks
Re: pair vs tuple in uniform initialization
Quote:
Originally Posted by
superbonzo
...
Thanks for the info. I'm getting a better hand at the notion of initializer list, and brace enclosed intialization. They can be confusing if you try to "learn by typing" rather than learn by actually reading a book. I think I get it now though.
It was the explicit on a double argument constructor that threw me off. The example you gave didn't compile, not because of the initiaizer list, but because the compiler can't build the tuple. It's nothing a bit of explicit can't solve:
Code:
std::list<std::tuple<std::string, std::string>> il{
std::tuple<std::string, std::string>{"Nygaard","Simula"},
std::tuple<std::string, std::string>{"Richards","BCPL"},
std::tuple<std::string, std::string>{"Ritchie","C"}
};
I must say that while I am a fan of the tuples, I hate the amount of text they take to write (I hate using "using"). The fact that they are explicit, and that make_tuple builds a tuple of the wrong type end up making their use (here) especially verbose.
No a big deal, but it doesn't quite have the elegance of the first exemple :(
Re: pair vs tuple in uniform initialization
Quote:
Originally Posted by
monarch_dodra
The example you gave didn't compile
can you post the compiler output ?
so, in the direct-list-initialization case only the outermost braces can match an explicit constructor ... that is, inner braces are always considered copy initializations. Ok, it makes sense, but I would also have liked a way of direct-initializing in a "nested" way ...
Re: pair vs tuple in uniform initialization
Quote:
Originally Posted by
superbonzo
can you post the compiler output ?
Sorry, should have posted it right from the beginning:
Code:
main.cpp|error: converting to 'std::tuple<std::basic_string<char>, std::basic_string<char> >' from initializer list would use explicit constructor 'std::tuple<_T1, _T2>::tuple(_U1&&, _U2&&) [with _U1 = const char (&)[8], _U2 = const char (&)[7], _T1 = std::basic_string<char>, _T2 = std::basic_string<char>]'|
This is what I get in both my first example, and with your code.
MinGW 4.6.2.