What is the purpose of std::make_pair vs the constructor of std::pair?
The difference is that with std::pair
you need to specify the types of both elements, whereas std::make_pair
will create a pair with the type of the elements that are passed to it, without you needing to tell it. That's what I could gather from various docs anyways.
See this example from http://www.cplusplus.com/reference/std/utility/make_pair/
pair <int,int> one;
pair <int,int> two;
one = make_pair (10,20);
two = make_pair (10.5,'A'); // ok: implicit conversion from pair<double,char>
Aside from the implicit conversion bonus of it, if you didn't use make_pair you'd have to do
one = pair<int,int>(10,20)
every time you assigned to one, which would be annoying over time...
As @MSalters replied above, you can now use curly braces to do this in C++11 (just verified this with a C++11 compiler):
pair<int, int> p = {1, 2};
Class template arguments could not be inferred from the constructor before C++17
Before C++17 you could not write something like:
std::pair p(1, 'a');
since that would infer template types from the constructor arguments, you had to write it explicitly as:
std::pair<int,char> p(1, 'a');
C++17 makes that syntax possible, and therefore make_pair
redundant.
Before C++17, std::make_pair
allowed us to write less verbose code:
MyLongClassName1 o1;
MyLongClassName2 o2;
auto p = std::make_pair(o1, o2);
instead of the more verbose:
std::pair<MyLongClassName1,MyLongClassName2> p{o1, o2};
which repeats the types, and can be very long.
Type inference works in that pre-C++17 case because make_pair
is not a constructor.
make_pair
is essentially equivalent to:
template<class T1, class T2>
std::pair<T1, T2> my_make_pair(T1 t1, T2 t2) {
return std::pair<T1, T2>(t1, t2);
}
The same concept applies to inserter
vs insert_iterator
.
See also:
- Why not infer template parameter from constructor?
- https://en.wikibooks.org/wiki/More_C++_Idioms/Object_Generator
Minimal example
To make things more concrete, we can observe the problem minimally with:
main.cpp
template <class MyType>
struct MyClass {
MyType i;
MyClass(MyType i) : i(i) {}
};
template<class MyType>
MyClass<MyType> make_my_class(MyType i) {
return MyClass<MyType>(i);
}
int main() {
MyClass<int> my_class(1);
}
then:
g++-8 -Wall -Wextra -Wpedantic -std=c++17 main.cpp
compiles happily, but:
g++-8 -Wall -Wextra -Wpedantic -std=c++14 main.cpp
fails with:
main.cpp: In function ‘int main()’:
main.cpp:13:13: error: missing template arguments before ‘my_class’
MyClass my_class(1);
^~~~~~~~
and requires instead to work:
MyClass<int> my_class(1);
or the helper:
auto my_class = make_my_class(1);
which uses a regular function instead of a constructor.
Difference for std::reference_wrapper
This comment mentions that std::make_pair
unwraps std::reference_wrapper
while the constructor does not, so that's one difference. TODO example.
Tested with GCC 8.1.0, Ubuntu 16.04.