Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Specialized inheritance of a templated class causes member function to return templated class type rather than inherited class type

Assume I have a base class like this:

template<typename T>
class Base {
public:
    Base& operator()(const T& value) {
        this->value = value;
        return *this;
    }
    T value;
};

Now I want to inherit from this class to create type-specific classes

class InheritedFloat : public Base<float> {} inheritedFloat;

Now here I try to catch this inheritance in a functon:

void function(const InheritedFloat& inherited) {
    std::cout << inherited.value << '\n';
}

Calling this function like this works fine, of course:

int main() {
    function(inheritedFloat); //(inheritedFloat is a global instance)

    return 0;
}

But when I try to call it with the operator()(const float& value){...} member function, function(const InheritedFloat& inherited){...} doesn't see it as a InheritedFloat-Type but instead as a Base<float>-Type:

int main() {
    function(inheritedFloat(10.f)); //error

    return 0;
}

Error:

Error   C2664   'void function(const InheritedFloat &)': cannot convert argument 1 from 'Base<float>' to 'const InheritedFloat &'

So how can I make operator()(const T& value){...} return InheritedFloat& instead of Base<float>&?


To clearify further, this is just a simplified example (of course). I have dozens of inheritance cases. So I can't just template-specify function()

template<typename T>
void function(const Base<T>& inherited) {
    std::cout << inherited.value << '\n';
}

because each inheritance needs to be treated differently. Types will overlap, so there will be multiple Base<std::size_t> cases, for example.

The whole code:

#include <iostream>

template<typename T>
class Base {
public:
    Base& operator()(const T& value) {
        this->value = value;
        return *this;
    }
    T value;
};

class InheritedFloat : public Base<float> {} inheritedFloat;


void function(const InheritedFloat& inherited) {
    std::cout << inherited.value << '\n';
}

int main() {
    function(inheritedFloat(10.f));

    return 0;
}

Thanks for reading, I appreciate any help!

like image 631
Stack Danny Avatar asked Dec 24 '22 10:12

Stack Danny


1 Answers

You can utilize CRTP here. By supplying extra template parameter you can make base class function return a reference to a derived class:

#include <iostream>

template<typename Derived, typename T>
class Base {
public:
    Derived & operator()(const T& value) {
        this->value = value;
        return *static_cast<Derived *>(this);
    }
    T value;
};

class InheritedFloat : public Base<InheritedFloat, float> {} inheritedFloat;


void function(const InheritedFloat& inherited) {
    std::cout << inherited.value << '\n';
}

int main() {
    function(inheritedFloat(10.f));

    return 0;
}

online compiler

like image 69
user7860670 Avatar answered Feb 01 '23 23:02

user7860670