让我们考虑一个简单的类
template< typename T >
class Wrapper {
public:
// Constructors?
private:
T wrapped;
};
它应该使用什么构造函数才能有效?
在 C++0x 之前,将有一个构造函数,它采用以下任一方式:
- const reference (
T const&
) - 如果类型T
是“重”, - 或 value (
T
) - 如果 typeT
是“light”。
确定类型T
是“重”还是“轻”并不容易。
可以假设只有内置类型(ints/floats/...)是“轻量级”的。但这并不完全正确,因为我们Wrapper<int>
最有可能也应该将其视为“轻”类型。
类似的库通过允许类型创建者将类型标记为“轻”(通过提供适当的专业化)boost::call_traits
来提供一些克服这一困难的方法。call_traits
否则将被视为“重”。似乎可以接受。
但是 C++0x 使情况变得更糟。因为现在您还有右值引用 ( T&&
),它允许有效地获取(一些)“重”对象。
正因为如此,现在您必须选择:
- 只是 const reference (
T const&
) - 如果类型T
是“重”并且不支持移动语义(因为要么没有 - 就像大型 POD - 或者没有写入并且你对此没有影响), - const 引用 (
T const&
) 和 rvalue 引用 (T&&
) - 如果类型T
是“重”并且确实支持移动语义, - just value (
T
) - 如果类型T
是“轻”或“重”但支持移动语义(即使复制了它也不会打扰使用,否则我们无论如何都必须从T const&
自己复制......)。
仍然不容易分辨哪些类型是“重的”,哪些是“轻的”(如前所述)。但是现在您也无法判断类型是否T
支持移动语义(或者您是否支持?)。
一旦你包装了多个值,这会变得更加烦人,因为可能的构造函数重载的数量呈指数增长。
这个问题有什么解决办法吗?
我想到了一些用于转发(完美转发)参数的模板构造函数,但我不确定这是否会按预期工作。而且它还允许提供不同类型的值,这些值将被转发给T
构造函数。这可能被认为是一项功能,但并非必须如此。