首页 文章

具有指定模板参数的C 11 make_pair无法编译

提问于
浏览
73

我刚刚玩了启用-std = c 11的g 4.7(后面的一个快照) . 我试图编译一些现有的代码库,一个失败的案例让我感到困惑 .

如果有人能解释发生了什么,我将不胜感激 .

这是代码

#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)),但是我在这种情况下没有失败't understand why it' .

确切的错误是:

test.cpp:在函数'int main()'中:test.cpp:11:83:错误:没有匹配函数来调用'make_pair(std :: string&,int)'test.cpp:11:83:注意:候选人是:在/gcc4.7/usr/local/lib/gcc/i686-pc-linux-gnu/4.7.0/../../../../include/c /4.7中包含的文件.0 / utility:72:0,来自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:注意:模板constexpr std :: pair :: __ 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:注意:模板参数推断/替换失败:test.cpp:11:83:注意:无法将's'(类型'std :: string ')转换为输入'std :: basic_string &&'

同样,这里的问题只是“发生了什么?”我知道我可以通过删除模板规范来解决问题,但我只是想知道这里的失败是什么 . 提前致谢 .

编辑:

  • g 4.4编译此代码没有问题 .

  • 正在删除-std = c 11也可以编译代码而没有任何问题 .

1 回答

  • 114

    这不是如何使用 std::make_pair ;你不应该明确指定模板参数 .

    C 11 std::make_pair 有两个参数,类型为 T&&U&& ,其中 TU 是模板类型参数 . 实际上,它看起来像这样(忽略返回类型):

    template <typename T, typename U>
    [return type] make_pair(T&& argT, U&& argU);
    

    当您调用 std::make_pair 并显式指定模板类型参数时,不会发生参数推断 . 相反,类型参数直接替换为模板声明,产生:

    [return type] make_pair(std::string&& argT, int&& argU);
    

    请注意,这两个参数类型都是右值引用 . 因此,它们只能绑定到右值 . 对于传递的第二个参数 7 ,这不是问题,因为这是一个右值表达式 . 但是, s 是一个左值表达式(它不是被移动的't a temporary and it isn') . 这意味着函数模板与您的参数不匹配,这就是您收到错误的原因 .

    那么,为什么当你没有明确指定模板参数列表中的 TU 时,它是否有效?简而言之,右值参考参数在模板中是特殊的 . 部分由于称为引用折叠的语言功能, A&& 类型的右值引用参数(其中 A 是模板类型参数)可以绑定到任何类型的 A .

    无论 A 是左值,右值,const限定,volatile限定还是不合格都无关紧要, A&& 可以绑定到该对象(同样,当且仅当 A 本身是模板参数时) .

    在您的示例中,我们进行调用:

    make_pair(s, 7)
    

    这里, sstd::string 类型的左值, 7int 类型的右值 . 由于您没有为函数模板指定模板参数,因此执行模板参数推导以确定参数是什么 .

    要将 s (一个左值)绑定到 T&& ,编译器会将 T 推导为 std::string& ,从而产生类型为 std::string& && 的参数 . 但是,没有对引用的引用,因此"double reference"折叠成 std::string& . s 是一场火柴 .

    7 绑定到 U&& 很简单:编译器可以推导 Uint ,产生类型为 int&& 的参数,该参数成功绑定到 7 ,因为它是一个右值 .

    这些新的语言功能有很多微妙之处,但是如果你遵循一个简单的规则,它就很容易:

    如果可以从函数参数中推导出模板参数,那么可以推导出它 . 除非绝对必须,否则不要明确提供参数 . 让编译器付出艰苦的努力,99.9%的时间它完全是你想要的 . 如果它不是你想要的,你通常会得到一个易于识别和修复的编译错误 .

相关问题