Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

const references in c++ templates

In a C++ template with the generic type T, I can use

const T &

to get a reference to a constant T. However, if now T itself is a reference type (like e.g. T = int &), the above term resolves to

int &

and not to

const int &

which quite makes sense, since any reference itself is always constant. However, is there still a way to require a

const T &

if T itself is a reference type?

Edit: sample code to evaluate (g++ compiler):

template <typename T> class TemplateClass
{
public:
    void foo(const T &bar) { }
};

int main()
{
    TemplateClass<int &> x;
    x.foo(0);   // <-- compile error: no conversion from int to int&
    return 0;
}
like image 700
emkey08 Avatar asked Nov 28 '11 21:11

emkey08


People also ask

Can you modify const reference?

But const (int&) is a reference int& that is const , meaning that the reference itself cannot be modified.

Is const reference a copy?

Not just a copy; it is also a const copy. So you cannot modify it, invoke any non-const members from it, or pass it as a non-const parameter to any function. If you want a modifiable copy, lose the const decl on protos .

When should we use a const reference and why?

When we create our own copy constructor, we pass an object by reference and we generally pass it as a const reference. One reason for passing const reference is, we should use const in C++ wherever possible so that objects are not accidentally modified.

What is a const reference?

A const reference is actually a reference to const. A reference is inherently const, so when we say const reference, it is not a reference that can not be changed, rather it's a reference to const. Once a reference is bound to refer to an object, it can not be bound to refer to another object.


2 Answers

Remove the reference:

template<typename T>
void Test(const typename std::remove_reference<T>::type & param)
{
        param = 20;
}

Now it works as expected.

like image 171
Pubby Avatar answered Sep 22 '22 14:09

Pubby


You can always use template specialisation to implement a different version for any kind of reference:

template <typename T> struct X {
  void foo(T const&);
};

template <typename T> struct X<T&> {
  void foo(T const&);
};

Now, X<int>::foo expects an int const& and X<int&>::foo expects an int const&, too.

However, it is not entirely clear from your question what you are trying to do exactly.


Edit: My g++ version (4.6.1) does not complain without template specialisation for the following

int i = 7;
X<int&>(i);

While it does for

X<int&>(7);

Which is correct IMO, because you try to convert a temporary (7) to a mutable reference (even if that is a reference to a const reference).


Edit 2: If you want to reduce duplicate code, then do not specialise your original class, but use this:

template <typename T> struct R {
  typedef T& Ref;
  typedef T const& ConstRef;
};

template <typename T> struct R<T&> {
  typedef T& Ref;
  typedef T const& ConstRef;
};

template<typename T> struct X {
  void foo(typename R<T>::ConstRef x);
};
like image 35
bitmask Avatar answered Sep 20 '22 14:09

bitmask