2

I'd like to initialize a list of 5-tuples of strings like this:

std::vector<std::tuple<std::string,std::string,std::string,std::string,std::string> >
    examples = 
  {
    {"/foo"                 ,"/"           ,"foo"        ,""   ,"foo"},
    {"/foo/"                ,"/"           ,"foo"        ,""   ,"foo"},
    {"/foo//"               ,"/"           ,"foo"        ,""   ,"foo"},
    {"/foo/./"              ,"/foo"        ,"."          ,""   ,""},
    {"/foo/bar"             ,"/foo"        ,"bar"        ,""   ,"bar"},
    {"/foo/bar."            ,"/foo"        ,"bar."       ,""   ,"bar"},
    {"/foo/bar.txt"         ,"/foo"        ,"bar.txt"    ,"txt","bar"},
    {"/foo/bar.txt.zip"     ,"/foo"        ,"bar.txt.zip","zip","bar.txt"},
    {"/foo/bar.dir/"        ,"/foo"        ,"bar.dir"    ,"dir","bar"},
    {"/foo/bar.dir/file"    ,"/foo/bar.dir","file"       ,""   ,"file"},
    {"/foo/bar.dir/file.txt","/foo/bar.dir","file.txt"   ,"txt","file"}
  };

This question asks why nested initializer lists can't be used for vector of tuples: the answers say to use std::make_tuple. But this makes my code look ridiculous:

std::vector<std::tuple<std::string,std::string,std::string,std::string,std::string> >
    examples = 
  {
    std::make_tuple<std::string,std::string,std::string,std::string,std::string>("/foo"                 ,"/"           ,"foo"        ,""   ,"foo"),
    std::make_tuple<std::string,std::string,std::string,std::string,std::string>("/foo/"                ,"/"           ,"foo"        ,""   ,"foo"),
    std::make_tuple<std::string,std::string,std::string,std::string,std::string>("/foo//"               ,"/"           ,"foo"        ,""   ,"foo"),
    std::make_tuple<std::string,std::string,std::string,std::string,std::string>("/foo/./"              ,"/foo"        ,"."          ,""   ,""),
    std::make_tuple<std::string,std::string,std::string,std::string,std::string>("/foo/bar"             ,"/foo"        ,"bar"        ,""   ,"bar"),
    std::make_tuple<std::string,std::string,std::string,std::string,std::string>("/foo/bar."            ,"/foo"        ,"bar."       ,""   ,"bar"),
    std::make_tuple<std::string,std::string,std::string,std::string,std::string>("/foo/bar.txt"         ,"/foo"        ,"bar.txt"    ,"txt","bar"),
    std::make_tuple<std::string,std::string,std::string,std::string,std::string>("/foo/bar.txt.zip"     ,"/foo"        ,"bar.txt.zip","zip","bar.txt"),
    std::make_tuple<std::string,std::string,std::string,std::string,std::string>("/foo/bar.dir/"        ,"/foo"        ,"bar.dir"    ,"dir","bar"),
    std::make_tuple<std::string,std::string,std::string,std::string,std::string>("/foo/bar.dir/file"    ,"/foo/bar.dir","file"       ,""   ,"file"),
    std::make_tuple<std::string,std::string,std::string,std::string,std::string>("/foo/bar.dir/file.txt","/foo/bar.dir","file.txt"   ,"txt","file")
  };

If I can't get rid of the std::make_tuple<...>, can I at least use typedef or using to remove the clutter in the code?

using StringQuintet = std::tuple<std::string,std::string,std::string,std::string,std::string>; doesn't help because std::make_tuple<...> needs just the tuples template arguments not the tuple type.

Is there a good way to clean up this boilerplate looking mess?

Alec Jacobson
  • 6,032
  • 5
  • 51
  • 88
  • 3
    Using explicit template arguments in `std::make_tuple` defeats its purpose. Just use `std::tuple` directly. – tkausl Sep 26 '18 at 02:57
  • 1
    the point of `make_tuple` is to deduce types from the initializers, so you don't have to specify the type list – M.M Sep 26 '18 at 02:58
  • 2
    Have you considered `array` ? – M.M Sep 26 '18 at 02:59
  • 1
    You can use a string operator literal (`"/foo"s`) – David G Sep 26 '18 at 03:00
  • 1
    std::make_tuple() is a function it will deduce the types so you don't need to explicitly mention them. Though you will need to use the `std::string` literal rather than the `C-String` literal. – Martin York Sep 26 '18 at 03:03
  • Everyone is mentioning that make_tuple doesn't need the template arguments. This is great! (missed that) I will happily accept or just close... – Alec Jacobson Sep 26 '18 at 03:04
  • Load it from a file? – Galik Sep 26 '18 at 03:04
  • 1
    Your original code should work with a C++17 compiler because `std::string` can be constructed implicitly from a `char const *`, see https://stackoverflow.com/a/32084829/241631 – Praetorian Sep 26 '18 at 03:21

2 Answers2

3
 std::make_tuple<std::string,std::string,std::string,std::string,std::string>("/foo"                 ,"/"           ,"foo"        ,""   ,"foo"),

you don't pass types to make tuple.

std::make_tuple("/foo"                 ,"/"           ,"foo"        ,""   ,"foo"),

you let the compiler deduce them. Alternatively:

std::make_tuple("/foo"s                 ,"/"s           ,"foo"s        ,""s   ,"foo"s),

to have std string literals (using namespace std::literals; to permit this).

Or:

using StringQuintet = std::tuple<std::string,std::string,std::string,std::string,std::string>;
// ...
StringQuintet("/foo"                 ,"/"           ,"foo"        ,""   ,"foo"),
Yakk - Adam Nevraumont
  • 262,606
  • 27
  • 330
  • 524
0

Use std::make_tuple:

using namespace std::string_literals;
....

std::make_tuple("/foo"s                 ,"/"s           ,"foo"s        ,""s   ,"foo"s),

....
Martin York
  • 257,169
  • 86
  • 333
  • 562