C++11中的std::make_pair

7

你好,我有以下代码:

bool PinManager::insertPin(const std::string& p_pinNumber, const std::string& p_mode)
{
    boost::shared_ptr<GPIOPin> pin(new GPIOPin(p_pinNumber, p_mode));
    if (pin)
    {
        m_pinsInUse.insert(std::make_pair<std::string, boost::shared_ptr<GPIOPin> >(p_pinNumber, pin));
        return true;
    }
    return false;
}

这段代码一直可以编译,但当我添加了-std=c++0x标志后,它无法编译,并显示以下错误信息:

[ 42%] Building CXX object gpioaccess/CMakeFiles/gpioaccess.dir/pinmanager/pinmanager.cpp.o
/home/pi/robot_2.0/trunk/gpioaccess/pinmanager/pinmanager.cpp: In member function 'bool gpioaccess::PinManager::insertPin(const string&, const string&)':
/home/pi/robot_2.0/trunk/gpioaccess/pinmanager/pinmanager.cpp:39:101: error: no matching function for call to 'make_pair(const string&, boost::shared_ptr<gpioaccess::GPIOPin>&)'
/home/pi/robot_2.0/trunk/gpioaccess/pinmanager/pinmanager.cpp:39:101: note: candidate is:
/usr/include/c++/4.6/bits/stl_pair.h:262:5: note: template<class _T1, class _T2> std::pair<typename std::__decay_and_strip<_T1>::__type, typename std::__decay_and_strip<_T2>::__type> std::make_pair(_T1&&, _T2&&)
gpioaccess/CMakeFiles/gpioaccess.dir/build.make:77: recipe for target 'gpioaccess/CMakeFiles/gpioaccess.dir/pinmanager/pinmanager.cpp.o' failed
make[2]: *** [gpioaccess/CMakeFiles/gpioaccess.dir/pinmanager/pinmanager.cpp.o] Error 1
CMakeFiles/Makefile2:75: recipe for target 'gpioaccess/CMakeFiles/gpioaccess.dir/all' failed
make[1]: *** [gpioaccess/CMakeFiles/gpioaccess.dir/all] Error 2
Makefile:75: recipe for target 'all' failed
make: *** [all] Error 2

我做了一些调查后发现之前编译通过可能只是一个bug,但是我仍然不确定如何解决。有人能指点一下正确的方向吗?

gcc --version的版本是gcc (Debian 4.6.3-14+rpi1) 4.6.3


4
make_pair 应该能够推断出参数类型,尝试删除显式的模板参数:std::make_pair(p_pinNumber, pin) - melak47
2
旁注:如果抛出异常,则“if(pin)”始终为真或无效。 - user2249683
@melak47 那就是问题所在,删除参数后代码就可以编译了。谢谢! - joshu
3
请不要在您的代码中附带行号。这会使将其复制粘贴到编辑器或在线编译器表单中变得更加困难,而且没有任何必要。 - Christian Hackl
@DieterLücking 很好的发现,感谢指出。 - joshu
4个回答

25

std::make_pair之间发生了改变。

中,它接受转发引用参数而不是值传递。这意味着通过显式指定其类型模板参数,您最终得到以下实例化:

std::make_pair<std::string , boost::shared_ptr<GPIOPin> >
             (std::string&&, boost::shared_ptr<GPIOPin>&&);

期望使用无名对象引用,无法绑定到左值。
不应显式指定std :: make_pair的类型模板参数。相反,应该让编译器自行推断它们:
std::make_pair(p_pinNumber, pin)

此外,自以来,在使用std::map时,您可以就地构造pair:
m_pinsInUse.emplace(p_pinNumber, pin);

中,您可以利用类模板参数推导,并构造没有指定类模板参数的std::pair:
std::pair(p_pinNumber, pin)

谢谢,很高兴知道。C++14的定义有一个额外的改变。 - user2249683
2
应该强调这确实是C++11中的破坏性变更。 - Christian Hackl
4
实际上,这只会对误用make_pair的低级代码造成破坏性变化。 - Jonathan Wakely
1
因为回答清晰、简洁,没有显得傲慢或不必要的批评,所以我点了赞。 - user2428400

9
std::make_pair 的主要作用是简化创建 std::pair,使你不需要指定模板参数,而让编译器来推导它们。
如果你使用显式的模板参数调用 std::make_pair<T, U>(t, u),就会失去函数的全部作用,因为你阻止了推导,而且浪费时间输入额外的字符,可能还会创建不必要的对象副本,而你只需使用 std::pair<T, U>(t, u) 即可(省去五个多余的无用字符)。
如果你正确地使用 std::make_pair,你可能甚至不会注意到它在 C++11 中发生了变化。如果你滥用它而毫无意义地提供模板参数,则在 C++11 中可能无法正常工作,因此不要这样做。
我在http://advogato.org/person/redi/diary/239.html上写了更详细的解释。

6
请注意,在C++11中,std::make_pair经常可以被初始化构造函数所取代。
m_pinsInUse.insert({p_pinNumber, pin});

1
除了@NexusSquared提供的答案之外: 您可以使用std::map的新emplace函数: m_pinsInUse.emplace(p_pinNumber, pin); 这甚至更短,并且在原地构造std::pair,而不是先构造它,然后将新构造的pair的内容复制到map的内存中。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接