考虑一个类 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 函数可以分别绑定左值和右值参数。根据实际参数,这可能会导致临时对象的创建,最终会导致复制赋值; 因此,此设计不支持 不可复制 类型。
使用 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
/非const
,volatile
/非volatile
,以及一般情况下的任何可转换类型,避免创建临时对象并将值直接传递给operator=
。现在支持了不可复制、可移动类型。可以通过static_assert
或std::enable_if
来消除可能不想要的绑定。
所以我的问题是:作为一种设计准则,C++11中所有(假设大多数)的setter函数都应该编写为接受通用引用的函数模板吗?
除了更繁琐的语法和在编写这些setter函数时无法使用类似Intellisense的辅助工具外,“尽可能编写接受通用引用的函数模板作为setter函数”的假设原则是否存在任何相关的缺点?
a
的字段,但仍会通过以其他方式存储从指定的A
实例中所需的任何属性来逻辑地实现set_a
。或者也许在将来,字段的值不会与所有其他数据成员正交,因此set_a
也可能更新其他内容。我知道,YAGNI,但如果类被称为URL
,即使我愿意始终拥有一个set_protocol
成员函数,我也不一定希望承诺公开具有类型为string
的protocol
数据成员。 - Steve Jessopa_changed()
事件怎么样?或者调试一下属性的变化... - leemes