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.
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;
};
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
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With