我有一个类似的功能(请不要关心通过引用临时返回。这只是解释问题的一个例子),
const foo<const int>& get_const()
{
foo<int> f;
return f;
}
这显然不会编译。我正在寻找一种方法来确保来电者不会更改T
的{{1}}。我该如何确保?
我已经看到了foo
的类似行为。 boost::shared_ptr
可转换为shared_ptr<T>
。我无法弄清楚它是如何做到的。
任何帮助都会很棒。
答案 0 :(得分:9)
编译器将foo<T>
和foo<const T>
视为两个完全不同且不相关的类型,因此foo
类需要明确支持此类,就像任何其他转换一样。如果您可以控制foo
类,则需要提供复制构造函数或隐式转换运算符(或两者)。
template<typename T>
class foo
{
public:
// Regular constructor
foo(T t) : t(t) {}
// Copy constructor (works for any type S convertable to T, in particular S = non-const T if T is const)
// Remember that foo<T> and foo<S> are unrelated, so the accessor method must be used here
template<typename S> foo (const foo<S>& copy) : t(copy.getT()) {}
// Accessor
T getT() const { return t; }
// Conversion operator
operator foo<const T> () const { return foo<const T>(t); }
private:
T t;
};
答案 1 :(得分:1)
假设Foo定义如下:
template<typename T> class Foo
{
public:
Foo(const T& value) : m_value(value) { }
const T& getValue() const { return m_value; }
void setValue(const T& value) { m_value = value; }
private:
T m_value;
};
然后,为了确保Foo的客户端不修改m_value(我认为这就是“我正在寻找一种方法来确保调用者不会改变f的T”),你需要to const限定Foo对象而不是它的模板参数,即
Foo<int> x(1);
x.setValue(2); // OK
const Foo<int> y(1);
y.setValue(2); // does not compile
因此,您的get_foo函数应返回const Foo<T>&
,而不是const Foo<const T>&
。
这是一个完整的,可编辑的例子:
#include <iostream>
template<typename T> class Foo
{
public:
Foo(const T& value) : m_value(value) { }
const T& getValue() const { return m_value; }
void setValue(const T& value) { m_value = value; }
private:
T m_value;
};
template<class T> class Owner
{
public:
Owner(const T& value) : m_foo(value) { }
Foo<T>& getFoo() { return m_foo; }
const Foo<T>& getConstFoo() const { return m_foo; }
private:
Foo<T> m_foo;
};
int main(int argc, char** argv)
{
Owner<int> x(1);
x.getFoo().setValue(2);
// x.getConstFoo().setValue(3); // will not compile
}
答案 2 :(得分:0)
如果我没弄错,boost::shared_ptr
实现有一个非显式构造函数,它将const T&
引用作为参数,然后在RHS的指针上使用const_cast
来删除const
,允许它们之间的隐式转换。
这样的事情:
shared_ptr(const shared_ptr<const T>& r) : ptr(const_cast<T*>(r.ptr)) {}
这就是你要找的东西吗?
答案 3 :(得分:0)
首先,你通过引用返回一个本地对象......这不好。
foo和foo是两种不同的类型,所以你必须编写代码(转换构造函数)来显式转换它们。
要想得到你想要的东西,请考虑一下:
template <typename T>
struct foo {T* t;};
const foo<int>& get_const(const foo<int>& f) {
return f;
}
foo<int> f;
const foo<int>& cf = get_const(f);
f.t = 0; // ok, f is not const
*cf.t = 0; // ok because cf.t is const but what cf.t points to is not
cf.t = 0; // compiler error cf.t is const and cannot be lvalue
foo<int>& cf = get_const(f); // compiler error, cannot convert non-const to const without const_cast
如果你正确地完成了封装并且只使用const getter和非const setter访问成员,那么这对你来说已经足够了。记住,如果人们真的想要改变你的对象,他们总是可以const_cast。正确性只是为了捕捉无意识的错误。