从“foo”转换为到“const foo” - C++

发布于 2024-08-22 14:13:10 字数 409 浏览 8 评论 0原文

我有一个类似的函数(请不要关心通过引用返回临时值。这只是解释问题的示例),

const foo<const int>& get_const()
{
    foo<int> f;
    return f;
}

这显然无法编译。我正在寻找一种方法来确保调用者不会更改 fooT 。我怎样才能确保这一点?

我已经看到 boost::shared_ptr 的类似行为。 shared_ptr 可转换为 const shared_ptr。我不明白它是如何做到这一点的。

任何帮助都会很棒。

I have a function like (please don't care about returning temporary by reference. This is just an example to explain the problem),

const foo<const int>& get_const()
{
    foo<int> f;
    return f;
}

This obviously won't compile. I am looking for a way to ensure callers won't change the T of foo. How can I ensure that?

I have seen the similar behavior for boost::shared_ptr. shared_ptr<T> is convertible to const shared_ptr<const T>. I couldn't figure out how it is doing this.

Any help would be great.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

还如梦归 2024-08-29 14:13:11

编译器将 foofoo 视为两个完全不同且不相关的类型,因此 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;
};

The compiler sees foo<T> and foo<const T> as two completely different and unrelated types, so the foo class needs to support this explicitly just as with any other conversion. If you have control over the foo class, you need to provide a copy constructor or an implicit conversion operator (or both).

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;
};
随心而道 2024-08-29 14:13:11

假设 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 (我假设这就是“我正在寻找一种方法来确保调用者不会更改foo"),您需要对 Foo 对象而不是其模板参数进行 const 限定,即

Foo<int> x(1);
x.setValue(2); // OK
const Foo<int> y(1);
y.setValue(2); // does not compile

因此,您的 get_foo 函数应返回 const Foo&,而不是 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
}

Assuming that Foo is defined something like this:

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;
};

Then, in order to ensure that clients of Foo do not modify m_value (I assume that this is what is meant by "I am looking for a way to ensure callers won't change the T of foo"), you need to const-qualify the Foo object rather than its template parameter, i.e.

Foo<int> x(1);
x.setValue(2); // OK
const Foo<int> y(1);
y.setValue(2); // does not compile

Therefore, your get_foo function should return a const Foo<T>&, not a const Foo<const T>&.

Here's a complete, compilable example:

#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
}
溇涏 2024-08-29 14:13:11

如果我没记错的话,boost::shared_ptr 实现有一个非显式构造函数,它接受 const T& 引用作为参数,然后使用 在 RHS 指针上使用 const_cast 来删除 const,从而允许它们之间的隐式转换。

像这样的事情:

shared_ptr(const shared_ptr<const T>& r) : ptr(const_cast<T*>(r.ptr)) {}

这是你要找的吗?

If I'm not mistaken, the boost::shared_ptr implementation has a non-explicit constructor that takes a const T& reference as an argument and then uses a const_cast on the RHS's pointer to remove the const, allowing implicit conversions between them.

Something like this:

shared_ptr(const shared_ptr<const T>& r) : ptr(const_cast<T*>(r.ptr)) {}

Is that what you're looking for?

白色秋天 2024-08-29 14:13:11

首先,您通过引用返回本地对象......这不好。

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 和非常量 setter 的成员,这对你来说应该足够了。请记住,如果人们真的想更改您的对象,他们总是可以 const_cast。常量正确性只是为了发现无意的错误。

First of all, you're returning a local object by reference...that's not good.

foo and foo are two different types so you'll have to write code (conversion constructors) to explicitly convert them.

To get what you wanted, consider this:

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

If you done your encapsulation correctly and only access members with const getter and non-const setters, this should be good enough for you. Remember if people really want to change your object, they can always const_cast. Const-correctness is only to catch unintentional mistakes.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文