Ferenc Deak
Ferenc Deak

Reputation: 35408

C++ template generalization for const type

I am doing a small research here, which requires at some stage, that I have different classes doing (or not doing) operation on some data, depending on its constness.

A small example is like this (http://coliru.stacked-crooked.com/a/75c29cddbe6d8ef6)

#include <iostream>

template <class T>
class funny
{
public:
    funny(T& a) : v(a) {v -= 1; }
    virtual ~funny() { v += 1; }
    operator T() {return v;}

private:
    T& v;
};

#define V(a) funny<decltype(a)>(a)

int main()
{
    char t[] = "ABC"; // <-- HERE

    if( V( t[0] ) == (char)'A')
    {
        std::cout << "Pass" << t[0];
    }
    else
    {
        std::cout << "No Pass" << t[0];
    }
}

Now, comes the question:

if I modify the line marked <-- HERE to be

const char t[] = "ABC";

I get the following compilation error:

main.cpp: In instantiation of 'funny<T>::funny(T&) [with T = const char&]':
main.cpp:21:7:   required from here
main.cpp:7:28: error: assignment of read-only location '((funny<const char&>*)this)->funny<const char&>::v'
  funny(T& a) : v(a) {v -= 1; }
                      ~~^~~~
main.cpp: In instantiation of 'funny<T>::~funny() [with T = const char&]':
main.cpp:21:7:   required from here
main.cpp:8:27: error: assignment of read-only location '((funny<const char&>*)this)->funny<const char&>::v'
  virtual ~funny() { v += 1; }
                     ~~^~~~

Which is totally understandable, since I try to modify a constant. Compiler is right here. However, I really need this to work also for const data, so I tried to create a const specialization of the template:

template <class T>
class funny <T const>
{
public:
    funny(const T& a) : v(a) {}
    operator T() {return v;}

private:
    const T& v;
};

But regardless, the compiler does not find it, and still tries to compile the non-const version.

Any ideas on how to make this happen?

Upvotes: 2

Views: 571

Answers (2)

Miles Budnek
Miles Budnek

Reputation: 30494

decltype(t[0]) deduces to const char&, which doesn't match your const char specialization. You have two options:

1) Change your specialization to template <class T> class funny <T const&>. That will work for this case, but won't work for const int FOO = 42; V(FOO);.

2) Change your V macro to always deduce to a non-reference type:

#define V(a) funny<typename std::remove_reference<decltype(a)>::type>(a)

Upvotes: 4

marcinj
marcinj

Reputation: 49976

Compiles if you change:

template <class T>
class funny <T const>

to:

template <class T>
class funny <const T&>

Upvotes: 1

Related Questions