在C++中是否有任何可接受的方法来区分对不可变对象的const引用与可变对象的const引用?
例如
class DataBuffer {
// ...
};
class Params {
// ...
};
class C {
public:
// Given references must be valid during instance lifetime.
C(const Params& immutableParameters, const DataBuffer& mutableDataBuffer) :
m_immutableParameters{immutableParameters},
m_mutableDataBuffer{mutableDataBuffer}
{
}
void processBuffer();
private:
const Params& m_immutableParameters;
const DataBuffer& m_mutableDataBuffer;
};
Run Code Online (Sandbox Code Playgroud)
这里的语义差异仅在名称中给出.
问题是const&实例变量只让您知道该实例不会修改该对象.界面中没有区别是否可以在其他地方修改它们,我认为这是一个有用的功能,能够在界面中进行描述.
通过类型系统表达这一点将有助于使接口更清晰,允许编译器捕获错误(例如C,在上面的示例中意外修改传递给实例的参数,在实例之外),并且可能有助于编译器优化.
假设答案是在C++中无法区分,可能有些东西可以通过一些模板魔术来实现吗?
Nic*_*las 11
不可变性不是 C++类型系统的一部分.因此,您无法区分不可变对象和可变对象.即使你能,std::as_const将永远毁了你试图这样做.
如果您正在编写一个需要对象不变的接口,最简单的方法就是调用软件工程的基本定理:"我们可以通过引入额外的间接层来解决任何问题." 因此,使不变性成为类型系统的一部分.例如(仅供参考:使用一些小型C++ 17库):
template<typename T>
class immutable
{
public:
template<typename ...Args>
immutable(std::in_place_t, Args &&...args) t(std::forward<Args>(args)...) {}
immutable() = default;
~immutable() = default;
immutable(const immutable &) = default;
//Not moveable.
immutable(immutable &&) = delete;
//Not assignable.
immutable operator=(const immutable &) = delete;
immutable operator=(immutable &&) = delete;
const T* operator->() const {return &t;}
const T& operator*() const {return t;}
private:
const T t;
};
Run Code Online (Sandbox Code Playgroud)
使用这种类型,无论用户如何声明它们,内部T都是不可变的.你的类现在应该采取的.并且由于无法通过现有的复制或移动来构造,因此用户无论何时想要将其作为参数传递都被强制使用.immutable<T>Cimmutable<Params>const&immutable<T>Timmutable<Params>
当然,你最大的危险是他们会暂时过关.但那是你已经需要解决的问题.
我不知道原因,但是你可以这样做:
struct C {
template<typename T, typename T2>
C(T&&, const T2&&) = delete;
C(const Params&, const DataBuffer&) { /*...*/ }
};
Run Code Online (Sandbox Code Playgroud)
通过声明一个由非const引用接受任何参数的构造函数,它总是比构造函数更好地匹配const&,因为不必添加cv-qualifier.
该const&构造函数是一个更好的匹配传递时const的参数,作为CV-预选赛并没有被删除.
DataBuffer db;
const Params cp;
C c{ cp, db }; // ok, second constructor call is chosen
Params p;
C c2{ p, db }; // error, constructor is deleted
Run Code Online (Sandbox Code Playgroud)
请注意,正如@IgorTandetnik 所说,您可以轻松地打破您的要求:
Params pa;
const Params& ref_pa = pa;
C c3{ ref_pa, db }; // ok, but shouldn't compile.
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
2273 次 |
| 最近记录: |