可能重复:
Preventing non-const lvalues from resolving to rvalue reference instead of const lvalue reference
Conflict between copy constructor and forwarding constructor
我有这些类需要存储std :: unique_ptr(改编为boost :: any):
class any
{
public:
any()
: content(0)
{
}
any(any const&) = delete;
any(any && other)
: content(other.content)
{
content = 0;
}
template<typename ValueType>
any(ValueType const& value)
: content(new holder<ValueType>(value))
{
}
template<typename ValueType>
any(ValueType && value,
typename std::enable_if<!std::is_lvalue_reference<ValueType>::value,
void>::type* = 0)
: content(new holder<ValueType>(std::move(value)))
{
}
~any()
{
delete content;
}
public: // modifiers
any & swap(any & rhs)
{
std::swap(content, rhs.content);
return *this;
}
any & operator=(const any &) = delete;
any & operator=(any && rhs)
{
return swap(rhs);
}
template<typename ValueType>
any & operator=(ValueType const& rhs)
{
any(rhs).swap(*this);
return *this;
}
template<typename ValueType>
typename std::enable_if<!std::is_lvalue_reference<ValueType>::value,
any&>::type operator=(ValueType && rhs)
{
any(std::move(rhs)).swap(*this);
return *this;
}
public: // queries
bool empty() const
{
return !content;
}
const std::type_info & type() const
{
return content ? content->type() : typeid(void);
}
private: // types
class placeholder
{
public: // structors
virtual ~placeholder()
{
}
public: // queries
virtual const std::type_info & type() const = 0;
};
template<typename ValueType>
class holder : public placeholder
{
public: // structors
template <class T>
holder(T && value)
: held(std::forward<T>(value))
{
}
holder & operator=(const holder &) = delete;
public: // queries
virtual const std::type_info & type() const
{
return typeid(ValueType);
}
public:
ValueType held;
};
private: // representation
template<typename ValueType>
friend ValueType * any_cast(any *);
template<typename ValueType>
friend ValueType * unsafe_any_cast(any *);
placeholder * content;
};
和这个测试用例:
any a;
any b(a);
b = a;
和这一个:
std::map<int, int> map({{1,1},{2,2}});
any b(map);
std::cout << map.size() << std::endl; // displays 0
令我恐惧的是,在gdb下,我注意到在构造和分配b
时(甚至从地图中)调用了移动构造函数和移动赋值运算符,即使我没有标记{{1}与a
并不是暂时的。有人可以解释原因吗?
答案 0 :(得分:0)
我的第一个回答是错误的。在再次阅读了非常难以理解的代码之后,我看到您已经明确提供了一个移动和默认构造函数,但没有复制构造函数。如果一个类有任何用户定义的构造函数(你有两个),编译器将不会为该类生成任何其他构造函数。因此,您的班级没有复制构造函数。
修改:所以,回到原来的答案(由您的评论提示)。 §12.8/ 7 [class.copy]说:
永远不会实例化成员函数模板来执行复制 类对象的类对象的类对象。 [实施例:
struct S { template<typename T> S(T); template<typename T> S(T&&); S(); }; S f(); const S g; void h() { S a( f() ); // does not instantiate member template; // uses the implicitly generated move constructor S a(g); // does not instantiate the member template; // uses the implicitly generated copy constructor }
-end example]
由于你的复制构造函数是一个成员模板,但你的移动构造函数不是,所以在这里选择后者(你的情况与那方面的例子不同)。