Question

I have some hard time implementing traits in C++, I tried to follow several examples from the internet but it still doesn't want to compile.

I use a Term class, which contains an Attribute, an Operator and sometimes a value. For example, age < 10 or color == red are (simple) terms. Different kinds of attributes or operators exists, that inherits from classes Attribute or TermOperator. Since a lot of methods of the term class will depend on the attribute and the operator, this is a template class. In order to simplify the manipulation of terms, I added an abstract class : AbstractTerm

class AbstractTerm {
protected:
    Attribute* pAttribute;
    TermOperator* pOperator;
public:
    virtual bool eval(Data *) const = 0;
};

template <typename ATT, typename OP>
class Term : AbstractTerm {
    typedef typename TermTraits<ATT,OP>::type  VALUE_TYPE;
private:
    typename TermTraits<ATT,OP>::type value;
public:
    bool eval(Data *) const;
};

The value I need to store in term will depend on both attribute & operator, so I use traits to obtain the right type to store the value.

template < typename ATT, typename OP>
struct TermTraits
{
    typedef int type;       
};

template <>
struct TermTraits<ListAttribute, TermOperator>
{
    typedef ListValue type;
};

template <>
struct TermTraits<NumericAttribute, TermOperator>
{
    typedef NumericIntValue type;
};

However, in the eval method when I use VALUE_TYPE I don't get the right type

template <> bool Term<NumericAttribute, TermOperatorEquals>::eval(Data _data) const {
    // VALUE_TYPE is a int, but it should be a NumericIntValue
    VALUE_TYPE *pValue = data->getValue<VALUE_TYPE>(this->pAttribute->getId());
    return !pValue->isEmpty && (this->value == pValue->value); // I get compilation errors here because pValue is a int* and not a 'NumericIntValue*'
};

I get the error:

error: request for member 'isEmpty' in '* pValue', 
which is of non-class type 'Term<NumericAttribute, 
TermOperatorExists>::VALUE_TYPE {aka int}. 

I can't figure out why it doesn't use the specialisation TermTraits<NumericAttribute, TermOperator>, since TermOperatorExists inherits from TermOperator.

Traits are a new concept to me, so maybe I made some obvious mistakes. If someone has a better way or simpler way to do this I'm also interested.

Was it helpful?

Solution

Although TermOperatorExists inherits from TermOperator, those are different types, so template specialization is not called for TermOperatorExists. You need to explicitly cast TermOperatorExists to its base class in order to get specialization called.

Example:

#include <iostream>

using namespace std;

class base
{
};
class derrived: public base
{
};

class test
{
    public:
    template <class T> void print(T arg)
    {
        std::cout << "test" << std::endl;
    }
};

template <>
void test::print<base>(base arg)
{
    std::cout << "base specialiation" << std::endl;
};

int main()
{
   cout << "Hello World" << endl; 
   base b;
   derrived d;


   test t;
    t.print<int>(1);
    t.print(b);
    t.print(d);
    t.print(static_cast<base>(d));
   return 0;
}

outputs:

Hello World
test
base specialiation
test
base specialiation
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top