1

I'm currently playing around with template metaprogramming. I'm trying to make a finite state machine by using tmp. I know that there are several implementations in the web but I want to implement one by myself as an exercise.

I'm trying to overload operators for templated derivatives of a templated base class inside the base class. Assume we have a base class:

template<typename Input>
class Base
{
public:
    virtual ~Base() = default;    
    virtual bool operator()(const Input& input) const = 0;

    template<typename Lhs, typename Rhs>
    constexpr Derivation1<Input, Lhs, Rhs> operator||(const Lhs& left, const Rhs& right) const;

    template<typename Lhs, typename Rhs>
    constexpr Derivation2<Input, Lhs, Rhs> operator&&(const Lhs& left, const Rhs& right) const;
};

and 2 of its derivations:

template<typename Input, typename... TSpecialized>
class Derivation1 : public Base<Input>
{
public:
    bool operator()(const Input& input) const override
    {
        // ...
    }
};

template<typename Input, typename... TSpecialized>
class Derivation2 : public Base<Input>
{
public:
    bool operator()(const Input& input) const override
    {
        // ...
    }
};

and the definition of the operators that we declared in the base class:

template <typename Input>
template <typename Lhs, typename Rhs>
constexpr Derivation1<Input, Lhs, Rhs> Base<Input>::operator||(const Lhs& left, const Rhs& right) const
{
    return Derivation1<Input, Lhs, Rhs>();
}

template <typename Input>
template <typename Lhs, typename Rhs>
constexpr Derivation2<Input, Lhs, Rhs> Base<Input>::operator&&(const Lhs& left, const Rhs& right) const
{
    return Derivation2<Input, Lhs, Rhs>();
}

The types Rhs and Lhs are derivations of the base class aswell.

When I try to use the operators like:

Derivation3<int, 10, 20> left;
Derivation4<int, 300, 290> right;

auto result = left || right;

I'm getting an error that says no overload of the operator matches the arguments. Both derivations have the same base type: Base<int> in which the overloads should be declared. The variable result should then be of type Derivation1 (like we declared it in the code above).

How do I overload the operatros properly in this case?

0

1 Answer 1

2

I found a solution. I've created a typedef in the base class:

template<typename Input>
class Base
{
public:
    virtual ~Base() = default;    
    virtual bool operator()(const Input& input) const = 0;

    typedef Input inputType;
};

and I moved the operator overloading outside of the class:

template <typename Lhs, typename Rhs>
constexpr Derivation1<typename Lhs::inputType, Lhs, Rhs> operator||(const Lhs& left, const Rhs& right)
{
    return Derivation1<typename Lhs::inputType, Lhs, Rhs>();
}

template <typename Lhs, typename Rhs>
constexpr Derivation2<typename Lhs::inputType, Lhs, Rhs> operator&&(const Lhs& left, const Rhs& right)
{
    return Derivation2<typename Lhs::inputType, Lhs, Rhs>();
}

This code works perfectly as intended.

Sign up to request clarification or add additional context in comments.

1 Comment

It's surprising if the compiler allowed the functions to be declared in Base at all; they needed friend specifiers there.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.