Template()的参数转发使构造函数参数变为常量

Argument forwarding for emplace() makes constructor arguments const

本文关键字:参数 构造函数 常量 转发 Template      更新时间:2023-10-16

我正在尝试使用emplace()来就地构造map<K,V>条目(使用Boost)。关键对象构造函数arg通过模板magic正确转发,但V object构造函数arg变为const,因此无法工作。

#include <boost/container/map.hpp>
class A {
  public:
    /**/     A( int n ) { }
    friend bool operator<( const A &a1, const A &a2 ) { return false; }
} ;
class B {
  public:
    /**/     B( const char *str ) { }
} ;
class C {
  public:
    /**/     C( B &b ) { }
} ;
int
main( int, char ** )
{
    boost::container::map<A,B>   m1;
    boost::container::map<A,C>   m2;
    B                            b( "Foo" );
    C                            c( b ); // <--- this works OK.
    m1.emplace( 1, "Hello" );
    m2.emplace( 2, b ); // <----- this fails!
}

错误为:

Error: /usr/local/include/boost/container/detail/pair.hpp:128:38: error: no matching function for call to C::C(const B&), second(::boost::forward<V>(v))

在最后一行中,关于模板参数转发的某些内容将b转换为const b。我知道一定有一个boost::bla_bla_bla我可以申请它,但我一直没能找到它。

有人能帮忙吗?

请注意,如果您使用-std=c++11(或更高版本)编译它,这将起作用。为什么会出现这种情况需要一点挖掘——我使用的是稍旧版本的boost(1.56),但我怀疑这在两个版本之间是否有太大变化。

使用emplace通常需要完美的转发。这意味着所有参数都是通过std::forward<Args>(args)...转发的。在底层,这依赖于引用折叠和移动语义——这都是C++11的领域,在C++03中没有类似的东西。

如果我们深入研究pair的boost代码(它实际上正在生成错误),那么这就是它试图调用的构造函数:

template<class U, class V>
pair(BOOST_FWD_REF(U) u, BOOST_FWD_REF(V) v)
   : first(::boost::forward<U>(u))
   , second(::boost::forward<V>(v))
{}

不幸的是,BOOST_FWD_REF(位于move/core.hpp中)是以下之一:

#define BOOST_FWD_REF(TYPE)
   const TYPE & 
//
#define BOOST_FWD_REF(TYPE)
    const TYPE & 
//

当编译器无法识别右值引用时,它将变为const TYPE&

boost档案列表中对此有一些讨论。

最简单的解决方案是简单地使用std=c++11进行编译。