模板类中的setter

时间:2015-04-07 13:06:22

标签: c++ c++11

我试图找到一种为模板类编写setter函数的好方法。对于非模板类,如果某种程度上是微不足道的,因为函数签名/实现依赖于参数类型。例如,如果参数类型为int,则下一个函数应该是最佳的:

void MyClass::Set(int value)
{
    myValue = value;
}

如果参数类型为std::vector,则下一个实现应接近最佳:

void MyClass::Set(std::vector<SomeType> value)
{
    std::swap(myValue, value);
}

作为正确的构造函数(移动或复制)将用于构造函数参数,并且不会发生不必要的复制,假设移动构造函数的成本可以忽略不计。

正如您所看到的,当更改类型时,两种实现都有缺点:如果第一个版本的类型更改为std::vector,则至少会创建一个不必要的副本,将实际成本增加2倍或者3。 如果在第二个版本2中类型更改为int,则会生成不必要的副本,从而将实际成本增加3倍。

你能否给我一个关于setter函数的一个很好的通用实现(可能有重载)?对于用作参数的任何类型,它应该是最佳的/接近最佳的。

PS:我宁愿不使用std::enable_if制作几个类型相关的setter,因为类会急剧增加。

2 个答案:

答案 0 :(得分:7)

您可以使用转发引用接受 rvalue 左值,然后将其转发给相应的移动或复制赋值运算符:

template <typename T>
void Set(T && value) {
    myValue = std::forward<T>(value);
}

答案 1 :(得分:0)

你应该有3次重载。

void Set( T&& t ) {
  v = std::move(t);
}
void Set( T const& t ) {
  v = t;
}
template<class U>
void Set( U&& u ) {
  v = std::forward<U>(u);
}

如果调用者在参数上使用{}初始化,或者如果调用者是函数的名称并且需要上下文或其他一些情况,则前两个允许隐式转换正常工作:将工作。这解决了一些更大的烦恼与#34;完美转发&#34;。

第三个为您提供了operator=超载的任何内容,以处理前两个未涵盖的内容。这是&#34;完美转发&#34;的一个例子,顾名思义是不完美的。

如果您只使用第3次重载,则最常见的问题是.Set( {construction args} )无法正常工作。

const&重载可能是多余的,但我不确定。

live example


// and sometimes:
template<class...Us>
void Set( Us&&...us ) {
  v = {std::forward<Us>(us)...};
}

第四个是安置集。在这种情况下(我们使用operator=),这实际上并没有用,但在某些情况下它可以。有关这样的emplace-accessor有用的示例,optional::value_or应该具有该重载。基本上,您可以直接构建目标值的情况,或者其他参数可能导致您构造值的情况,这很有用:如果您执行{std::forward<Us>(us)...}总是也可能在外部使用.Set( {args...} ),它调用上面的第一个重载。