1

How can someone make this code compile:

#include <iostream>
using namespace std;

enum E { A, B};

template< E x>
class C {
public:
    #if( x == A)
        static void foo() {
            cout << "A";
        }
    #elif( x == B)
        static void goo() {
            cout << "B";
        }
    #endif
};


int main() {
    C< A>::foo();
    C< B>::goo();

    return 0;
}

error: ‘goo’ is not a member of ‘C<(E)1u>’

I have two big classes which differs only a few lines, so I wanted to make enum template. The problem is that this lines have using keyword in them, so I don't know what to put there.

Is there some correct way to do it?

PS> I'm have to use C++03.

EDIT: A little clarification. I know about template<> construction, but I don't wanted to use it because this way I got a lot of code duplication. Maybe I can somehow make partial "template instanciation" (if this is correct term for template<>)?

Suppose I have two classes (and I will not have more):

class A {
public:
//…a lot of code…
//few lines that differs in A and B
}

class B {
//…the same mass of code…
//few lines that differs in A and B
}

So I decided to make template on enum:

enum E { A, B}
template< E>
class C{
//…common code…
}

Now I don't know what to do with this few lines that differs in A and B. I know that common way is to make template instanciation, but then I'll get exactly what I had with classes A and B.

From the OOP point I should use common Base for A and B. But the problem is that A and B is already the same. They differs only with line:

using CanStoreKeyValue< QString, Request>::set;
using CanStoreKeyValue< QString, Response>::set;

where Response and Request are typedefs. Moreover, in my code A and B are childs of the same templated abstract class. And of course they inherit it with different template param. This somehow brokes using of template enum — compiler just can't see that some virtual methods a no longer pure. So… that's why I'm asking what I'm asking. I thought that preprocessor could interact with template engine with #if-directives (on the end, they both are compile time processes).

Valentin T.
  • 519
  • 3
  • 12

2 Answers2

5

You cannot use preprocessor to achieve what you are trying to do. What you need is a template specialization:

enum E { A, B};

template< E x>
class C;

template <>
class C<A> {
public:
    static void foo() {
        cout << "A";
    }
};

template <>
class C<B> {
public:
    static void goo() {
        cout << "B";
    }
};

Your updated problem still can be resolved by template specialization:

enum E { A, B };

template< E x >
struct CanStoreKeyValueHelper;

template<>
struct CanStoreKeyValueHelper<A> {
    typedef CanStoreKeyValue< QString, Request>::set type;
};

template<>
struct CanStoreKeyValueHelper<B> {
    typedef CanStoreKeyValue< QString, Response>::set type;
};

template< E x>
class SuperPuperBigClass {
public:
    typedef typename CanStoreKeyValueHelper<x>::type set;
    ...
};

But it is not clear why you do not make it as simple as:

template<class T>
class SuperPuperBigClass {
public:
    typedef typename CanStoreKeyValue<QString, T>::set set;
};

and instantiate it with Request and Response type

Slava
  • 43,454
  • 1
  • 47
  • 90
2

If you don't want specialization, I suppose constraining the functions with SFINAE is an option (Live at coliru):

template <E x>
class C {
public:
    template <E y = x>
    static typename std::enable_if<y == A>::type foo() {
        cout << "A";
    }

    template <E y = x>
    static typename std::enable_if<y == B>::type goo() {
        cout << "B";
    }
};

But if code duplication is your only issue, use specialization and put the common code in a base class (Live at Coliru), it's a bit cleaner:

class C_base {};

template <E x>
class C : public C_base {};

template <>
class C<A> : public C_base {
public:
    static void foo() {
        cout << "A";
    }
};

template <>
class C<B> : public C_base {
public:
    static void goo() {
        cout << "B";
    }
};
Community
  • 1
  • 1
Casey
  • 41,449
  • 7
  • 95
  • 125