是否应将C ++ 11中的所有/大多数setter函数编写为接受通用引用的函数模板?

时间:2013-01-07 14:02:54

标签: c++ c++11 move-semantics perfect-forwarding universal-reference

考虑具有X成员变量的类N,每个可复制可移动类型,以及N对应的setter功能。 在C ++ 98中,X的定义可能如下所示:

class X
{
public:
    void set_a(A const& a) { _a = a; }
    void set_b(B const& b) { _b = b; }
    ...
private:
    A _a;
    B _b;
    ...
};

上面的类X的Setter函数可以绑定到lvalue和rvalue参数。根据实际参数,此可能导致创建临时,最终导致复制分配;因此,此设计不支持不可复制的类型。

使用C ++ 11,我们可以移动语义,完美转发和通用引用(Scott Meyers的术语),通过这种方式重写它们,可以更有效和广泛地使用setter函数:

class X
{
public:
    template<typename T>
    void set_a(T&& a) { _a = std::forward<T>(a); }

    template<typename T>
    void set_b(T&& b) { _b = std::forward<T>(b); }
    ...
private:
    A _a;
    B _b;
    ...
};

通用引用可以绑定到const /非 - constvolatile /非 - volatile,也可以绑定到任何可转换类型,避免创建临时引用将值直接传递给operator =。现在支持不可复制的可移动类型。可能会通过static_assertstd::enable_if消除不需要的绑定。

所以我的问题是:作为设计指南,C ++ 11中的所有(比如说,大多数)setter函数是否应该被编写为接受通用引用的函数模板?

除了在这些setter函数中编写代码时使用类似Intellisense的帮助工具的语法更加繁琐和不可能,假设原则“写入setter函数作为接受通用引用的函数模板时,是否存在任何相关的缺点可能“?

1 个答案:

答案 0 :(得分:37)

您知道A类和B类,因此您知道它们是否可移动,以及最终是否需要此设计。对于类似std::string的内容,除非您知道此处存在性能问题,否则更改现有代码会浪费时间。如果您正在处理auto_ptr,则需要将其删除并使用unique_ptr

如果您不知道更具体的内容,通常首选按值 - 例如

void set_a(A a) { _a = std::move(a); }

这允许使用A的任何构造函数,除了可移动性之外不需要任何东西,并提供相对直观的界面。