std::make_pair
的目的是创建一个 std::pair
对象。
为什么不能直接使用std::pair<int, char>(0, 'a')
?
这两种方法之间有什么区别吗?
(由于CTAD,此答案仅适用于C++14及更早版本)
区别在于使用std::pair
时需要指定两个元素的类型,而std::make_pair
将创建一个具有传递给它的元素类型的对,而无需您告诉它。这是我从各种文档中收集到的信息。
请参见来自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>
除了其隐式转换的优势之外,如果您没有使用 make_pair,您将不得不执行以下操作
one = pair<int,int>(10,20)
std::make_pair
。显然这只是为了方便。 - user542687one = {10, 20}
这种语法,但我手头没有C++11编译器来进行检查。 - MSaltersmake_pair
可以用于无名类型,包括结构体、联合体、lambda 表达式和其他类型。 - Mooing Duck在C++17之前,无法从构造函数中推断出类模板参数
在C++17之前,您无法编写以下内容:
std::pair p(1, 'a');
由于这将从构造函数参数中推断模板类型,因此您需要明确编写它:
std::pair<int,char> p(1, 'a');
make_pair
变得多余。std::make_pair
允许我们编写更简洁的代码:MyLongClassName1 o1;
MyLongClassName2 o2;
auto p = std::make_pair(o1, o2);
而不是更冗长的:
std::pair<MyLongClassName1,MyLongClassName2> p{o1, o2};
该部分代码会重复使用类型,并且可能非常冗长。
类型推断在早于C++17的版本中能够工作是因为make_pair
不是一个构造函数。
make_pair
本质上等同于:
template<class T1, class T2>
std::pair<T1, T2> my_make_pair(T1 t1, T2 t2) {
return std::pair<T1, T2>(t1, t2);
}
inserter
和 insert_iterator
。最小示例
为了使事情更具体化,我们可以通过以下方式最简单地观察问题:
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);
}
g++-8 -Wall -Wextra -Wpedantic -std=c++17 main.cpp
编译时没有错误,但是:
g++-8 -Wall -Wextra -Wpedantic -std=c++14 main.cpp
main.cpp: In function ‘int main()’:
main.cpp:13:13: error: missing template arguments before ‘my_class’
MyClass my_class(1);
^~~~~~~~
并且需要代替工作:
MyClass<int> my_class(1);
auto my_class = make_my_class(1);
std::reference_wrapper
的区别
这条评论提到std::make_pair
会解包std::reference_wrapper
,而构造函数则不会,这是一个区别。TODO示例。make_pair
变得多余。但是为什么在 C++17 中std::make_pair
没有被弃用呢? - andreeemake_pair
解开引用包装器,因此它与 CTAD 有所不同。 - L. F.如@MSalters在上面回答的那样,在C++11中现在可以使用花括号来实现这一点(我刚刚使用C++11编译器验证了这一点):
pair<int, int> p = {1, 2};
使用make_pair
和直接调用指定类型参数的pair
构造函数之间没有区别。std::make_pair
在类型较为冗长时更加方便,因为模板方法可以根据给定的参数进行类型推导。
例如,
std::vector< std::pair< std::vector<int>, std::vector<int> > > vecOfPair;
std::vector<int> emptyV;
// shorter
vecOfPair.push_back(std::make_pair(emptyV, emptyV));
// longer
vecOfPair.push_back(std::pair< std::vector<int>, std::vector<int> >(emptyV, emptyV));
vecOfPair.emplace_back(emptyV, emptyV);
- DarioPstd::make_pair
就是一个简单的例子,根据 std::make_pair
函数的实际参数返回 std::pair
模板的一个实例。template <class T, class U>
std::pair <T, U>
make_pair(T t, U u)
{
return std::pair <T, U> (t,u);
}
&&
。 - Justme0make_pair相比于直接构造函数会创建额外的副本。我总是使用typedef为我的pair提供简单的语法。
以下是Rampal Chaudhary提供的示例,展示了它们之间的区别:
class Sample
{
static int _noOfObjects;
int _objectNo;
public:
Sample() :
_objectNo( _noOfObjects++ )
{
std::cout<<"Inside default constructor of object "<<_objectNo<<std::endl;
}
Sample( const Sample& sample) :
_objectNo( _noOfObjects++ )
{
std::cout<<"Inside copy constructor of object "<<_objectNo<<std::endl;
}
~Sample()
{
std::cout<<"Destroying object "<<_objectNo<<std::endl;
}
};
int Sample::_noOfObjects = 0;
int main(int argc, char* argv[])
{
Sample sample;
std::map<int,Sample> map;
map.insert( std::make_pair( 1, sample) );
//map.insert( std::pair<int,Sample>( 1, sample) );
return 0;
}
std::move
在insert
内部以及/或者在对sample
的引用周围得到了相同的结果。只有当我将std::map<int,Sample>
更改为std::map<int,Sample const&>
时,才会减少构造对象的数量,并且只有在删除复制构造函数时才能消除所有副本(显然)。在进行这两个更改后,我的结果包括一个默认构造函数调用和两个相同对象的析构函数调用。我认为我可能漏掉了什么。(g++ 5.4.1,c++11) - John Pemplace
而不是insert
。虽然这不是我的专业领域,如果我可以这么说,但C++11引入的复制/移动语义对我帮助很大。 - John Pstd::make_pair(1, 2);
std::pair<int, int>(1, 2);
只需使用
{1, 2};
{1, 2}
可用于初始化一个pair,但不会确定pair的类型。即当使用auto时,您必须在右侧指定pair的类型: auto p = std::pair{"Tokyo"s, 9.00};
。 - Markusstd::make_pair
了,因为它在我的观点下是“有问题的”(至少对我来说不直观)。考虑以下示例:using Id = int;
std::vector<std::string> string_pool;
std::map<std::string_view, Id> str_to_id_map;
std::map
中;str_to_id_map.insert(std::make_pair(string_pool.back(), 42));
str_to_id_map.insert({string_pool.back(), 42});
std::make_pair
是多余的。下面有一个详细解释。 - Drew Dormann{ 0,'a' }
(任何有一定时间编写JavaScript代码的人都会特别喜欢这个)。 - Andrewstd::make_pair(vec.cbegin(), vec.cend())
和std::pair<std::vector<std::string>::const_iterator, std::vector<std::string>::const_iterator>(vec.cbegin(), vec.cend())
有何区别? - Mooing Duck