Initializing std::string embedded in std::pair with non-1-argument ctor?

905 views Asked by At

Is it possible to construct a std::pair if I want to construct the embedded std::string with a constructor that takes more than 1 argument?

E.g., this is legal:

#include <iostream>
#include <utility>
#include <string>

int main()
{
  std::pair<int, int> pair(2, 3);
  return 0;
}

...and this is legal:

#include <iostream>
#include <utility>
#include <string>

int main()
{
  std::pair<int, std::string> pair(2, "hello");
  return 0;
}

...but I wonder if something like the following is possible:

#include <iostream>
#include <utility>
#include <string>

int main()
{
  std::pair<int, std::string> pair{2, {"hello", 3}}; //Unclear if some variation/combination of parentheses and curly braces can make this legal.
  return 0;
}

I think the above is correct syntax to use "uniform initializer lists", but this won't work for my purposes because I'm using a pre-C++11 compiler. Is there some way to pull this off with pre-C++11 syntax?

To clarify, I'm trying to use this std::string constructor:

basic_string( const CharT* s,
              size_type count,
              const Allocator& alloc = Allocator() );

As context on why I'm asking this, this is for academic curiosity (correct me if wrong): I think doing one-line construction like this is more efficient because the std::pair and its members are simply created and initialized all in one go. Whereas if I did something like this (using C++11 syntax)...

#include <iostream>
#include <utility>
#include <string>

int main()
{
  std::pair<int, int> pair(2, 3);
  std::pair<int, std::string> pair2 = {2, {"hello", 3}};
  return 0;
}

...then I'm technically creating a std::pair<int, std::string> whose members are default-contructed, followed by invoking std::pair's operator=, followed by invoking the operator= on the pair's members.

1

There are 1 answers

5
Vlad from Moscow On BEST ANSWER

Just write:

std::pair<int, std::string> pair( 2, std::string( "hello", 3 ) ); 

As for this declaration:

std::pair<int, std::string> pair2 = {2, {"hello", 3}};

then in fact it is equivalent to this declaration:

std::pair<int, std::string> pair{2, { "hello", 3}};

due to the copy constructor elision. Take into account that there is neither assignment operator because it is a declaration.

Consider the following example:

#include <iostream>
#include <string>

int main()
{
    struct Pair
    {
        std::string s;
        int i;
        Pair(int i, const std::string &s) : i(i), s(s)
        {
            std::cout << "Pair( int, std::string )" << std::endl;
        }

        Pair( const Pair &p) : i(p.i), s(p.s)
        {
            std::cout << "Pair( const Pair & )" << std::endl;
        }
    };

    Pair p1{ 2, { "hello", 3 } };
    Pair p2 = { 2, { "hello", 3 } };
}

The program output is:

Pair( int, std::string )
Pair( int, std::string )