C++11 make_pair with specified template parameters doesn#39;t compile(具有指定模板参数的 C++11 make_pair 无法编译)
问题描述
我只是在启用 -std=c++11 的情况下使用 g++ 4.7(后来的快照之一).我试图编译我现有的一些代码库,一个失败的案例让我有些困惑.
I was just playing around with g++ 4.7 (one of the later snapshots) with -std=c++11 enabled. I tried to compile some of my existing code base and one case that failed somewhat confuses me.
如果有人能解释发生了什么,我将不胜感激.
I would appreciate if someone can explain what is going on.
代码如下:
#include <utility>
#include <iostream>
#include <vector>
#include <string>
int main ( )
{
std::string s = "abc";
// 1 ok
std::pair < std::string, int > a = std::make_pair ( s, 7 );
// 2 error on the next line
std::pair < std::string, int > b = std::make_pair < std::string, int > ( s, 7 );
// 3 ok
std::pair < std::string, int > d = std::pair < std::string, int > ( s, 7 );
return 0;
}
我知道 make_pair 意味着用作 (1) 的情况(如果我指定类型,那么我不妨使用 (3)),但我不明白为什么在这种情况下它失败了.
I understand that make_pair is meant to be used as the (1) case (if I specify the types, then I might as well use (3)), but I don't understand why it's failing in this case.
确切的错误是:
test.cpp: In function ‘int main()’:
test.cpp:11:83: error: no matching function for call to ‘make_pair(std::string&, int)’
test.cpp:11:83: note: candidate is:
In file included from /gcc4.7/usr/local/lib/gcc/i686-pc-linux-gnu/4.7.0/../../../../include/c++/4.7.0/utility:72:0,
from test.cpp:1:
/gcc4.7/usr/local/lib/gcc/i686-pc-linux-gnu/4.7.0/../../../../include/c++/4.7.0/bits/stl_pair.h:274:5:
note: template<class _T1, class _T2> constexpr std::pair<typename std::__decay_and_strip<_T1>::__type, typename std::__decay_and_strip<_T2>::__type> std::make_pair(_T1&&, _T2&&)
/gcc4.7/usr/local/lib/gcc/i686-pc-linux-gnu/4.7.0/../../../../include/c++/4.7.0/bits/stl_pair.h:274:5:
note: template argument deduction/substitution failed:
test.cpp:11:83: note: cannot convert ‘s’ (type ‘std::string {aka std::basic_string<char>}’) to type ‘std::basic_string<char>&&’
同样,这里的问题只是发生了什么事?"我知道我可以通过删除模板规范来解决问题,但我只想知道这里到底发生了什么问题.
Again, the question here is just "what's going on?" I know that I can fix the problem by removing the template specification, but I just want to know what's failing here under the covers.
- g++ 4.4 编译这段代码没有问题.
- 删除 -std=c++11 也可以正常编译代码.
推荐答案
这不是 std::make_pair 的用途;您不应该明确指定模板参数.
This is not how std::make_pair is intended to be used; you are not supposed to explicitly specify the template arguments.
C++11 std::make_pair 有两个参数,类型为 T&& 和 U&&,其中T 和 U 是模板类型参数.实际上,它看起来像这样(忽略返回类型):
The C++11 std::make_pair takes two arguments, of type T&& and U&&, where T and U are template type parameters. Effectively, it looks like this (ignoring the return type):
template <typename T, typename U>
[return type] make_pair(T&& argT, U&& argU);
当您调用 std::make_pair 并显式指定模板类型参数时,不会发生参数推导.相反,类型参数直接替换到模板声明中,产生:
When you call std::make_pair and explicitly specify the template type arguments, no argument deduction takes place. Instead, the type arguments are substituted directly into the template declaration, yielding:
[return type] make_pair(std::string&& argT, int&& argU);
请注意,这两种参数类型都是右值引用.因此,它们只能绑定到右值.这对于您传递的第二个参数 7 来说不是问题,因为那是一个右值表达式.然而,s 是一个左值表达式(它不是临时的,也没有被移动).这意味着函数模板与您的参数不匹配,这就是您收到错误的原因.
Note that both of these parameter types are rvalue references. Thus, they can only bind to rvalues. This isn't a problem for the second argument that you pass, 7, because that is an rvalue expression. s, however, is an lvalue expression (it isn't a temporary and it isn't being moved). This means the function template is not a match for your arguments, which is why you get the error.
那么,为什么不明确指定模板参数列表中的 T 和 U 是什么?简而言之,右值引用参数在模板中是特殊的.部分由于称为 reference collapsing 的语言功能,一个右值引用A&& 类型的参数,其中 A 是模板类型参数,可以绑定到任何类型的 A.
So, why does it work when you don't explicitly specify what T and U are in the template argument list? In short, rvalue reference parameters are special in templates. Due in part to a language feature called reference collapsing, an rvalue reference parameter of type A&&, where A is a template type parameter, can bind to any kind of A.
A 是左值、右值、const-qualified、volatile-qualified 还是 unqualified 都没有关系,A&& 可以绑定到那个对象(同样,当且仅当 A 本身就是一个模板参数).
It doesn't matter whether the A is an lvalue, an rvalue, const-qualified, volatile-qualified, or unqualified, an A&& can bind to that object (again, if and only if A is itself a template parameter).
在您的示例中,我们进行调用:
In your example, we make the call:
make_pair(s, 7)
这里,s 是 std::string 类型的左值,7 是 int.由于您没有为函数模板指定模板参数,因此执行模板参数推导以找出参数是什么.
Here, s is an lvalue of type std::string and 7 is an rvalue of type int. Since you do not specify the template arguments for the function template, template argument deduction is performed to figure out what the arguments are.
要将左值 s 绑定到 T&&,编译器将 T 推导出为 std::string&,产生 std::string& 类型的参数&&.但是,没有对引用的引用,所以这个双重引用"折叠成 std::string&.s 是一个匹配项.
To bind s, an lvalue, to T&&, the compiler deduces T to be std::string&, yielding an argument of type std::string& &&. There are no references to references, though, so this "double reference" collapses to become std::string&. s is a match.
将7绑定到U&&很简单:编译器可以推导出U为int,产生一个 int&& 类型的参数,它成功绑定到 7,因为它是一个右值.
It's simple to bind 7 to U&&: the compiler can deduce U to be int, yielding a parameter of type int&&, which binds successfully to 7 because it is an rvalue.
这些新的语言特性有很多微妙之处,但如果你遵循一个简单的规则,那就很容易了:
There are lots of subtleties with these new language features, but if you follow one simple rule, it's pretty easy:
如果一个模板参数可以从函数参数中推导出来,就让它被推导出来.除非绝对必须,否则不要显式提供参数.
If a template argument can be deduced from the function arguments, let it be deduced. Don't explicitly provide the argument unless you absolutely must.
让编译器完成繁重的工作,无论如何,它在 99.9% 的情况下都会是您想要的.如果它不是您想要的,您通常会得到一个易于识别和修复的编译错误.
Let the compiler do the hard work, and 99.9% of the time it'll be exactly what you wanted anyway. When it isn't what you wanted, you'll usually get a compilation error which is easy to identify and fix.
这篇关于具有指定模板参数的 C++11 make_pair 无法编译的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!
本文标题为:具有指定模板参数的 C++11 make_pair 无法编译
基础教程推荐
- 如果我为无符号变量分配负值会发生什么? 2022-01-01
- 为什么派生模板类不能访问基模板类的标识符? 2021-01-01
- CString 到 char* 2021-01-01
- 初始化列表*参数*评估顺序 2021-01-01
- 为什么 typeid.name() 使用 GCC 返回奇怪的字符以及如 2022-09-16
- 我应该对 C++ 中的成员变量和函数参数使用相同的名称吗? 2021-01-01
- 通过引用传递 C++ 迭代器有什么问题? 2022-01-01
- 为什么 RegOpenKeyEx() 在 Vista 64 位上返回错误代码 2021-01-01
- 非静态 const 成员,不能使用默认赋值运算符 2022-10-09
- GDB 显示调用堆栈上函数地址的当前编译二进制文 2022-09-05
