c++polymorphismvirtual-functions

Overriding derived virtual method in a templated class


I have the code below where I want foo to be implemented by the derived class but used within baseclass by bar methods. But I need foo to handle two cases where one of the inputs and the output type is:

Something like this, but this mixes static and dynamic polymorphism.

template <typename R>
virtual container_t<R> foo(const R& value1, const T& value2) const = 0;

But the following does not build with T = bool as calling foo becomes ambiguous. How do I solve this?

#include <iostream>
#include <vector>

template <template <typename> typename container_t, typename T>
class BaseClass {
public:
    virtual container_t<T> foo(const T& value1, const T& value2) const = 0;
    virtual container_t<bool> foo(bool value1, const T& value2) const = 0;

    container_t<T> bar_t() const {
        return foo(T(0), T(0));
    }
    container_t<bool> bar_bool() const {
        return foo(false, T(0));
    }
};

template <typename T>
class DerivedClass : public BaseClass<std::vector, T> {
public:
    using BaseClass<std::vector, T>::bar_t;
    using BaseClass<std::vector, T>::bar_bool;

    DerivedClass() {}

    std::vector<T> foo(const T& value1, const T& value2) const override {
        return std::vector<T>(8, value1);
    }

    std::vector<bool> foo(bool value1, const T& value2) const override {
        return std::vector<bool>(8, value1);
    }
};

int main() {

    DerivedClass<int> int_instance;
    std::cout << int_instance.bar_t().size() << std::endl;
    std::cout << int_instance.bar_bool().size() << std::endl;

    DerivedClass<bool> bool_instance;
    std::cout << bool_instance.bar_t().size() << std::endl;
    std::cout << bool_instance.bar_bool().size() << std::endl;

    return 0;
}

Compiler error:

1>main.cpp
1>main.cpp(15,1): error C2668: 'BaseClass<std::vector,T>::foo': ambiguous call to overloaded function
1>        with
1>        [
1>            T=bool
1>        ]
1>main.cpp(9,31): message : could be 'std::vector<bool,std::allocator<bool>> BaseClass<std::vector,T>::foo(bool,const T &) const'
1>        with
1>        [
1>            T=bool
1>        ]
1>main.cpp(8,28): message : or 'std::vector<bool,std::allocator<bool>> BaseClass<std::vector,T>::foo(const T &,const T &) const'
1>        with
1>        [
1>            T=bool
1>        ]
1>main.cpp(15,1): message : while trying to match the argument list '(bool, T)'
1>        with
1>        [
1>            T=bool
1>        ]
1>main.cpp(14): message : while compiling class template member function 'std::vector<bool,std::allocator<bool>> BaseClass<std::vector,T>::bar_bool(void) const'
1>        with
1>        [
1>            T=bool
1>        ]
1>main.cpp(45): message : see reference to function template instantiation 'std::vector<bool,std::allocator<bool>> BaseClass<std::vector,T>::bar_bool(void) const' being compiled
1>        with
1>        [
1>            T=bool
1>        ]
1>main.cpp(20): message : see reference to class template instantiation 'BaseClass<std::vector,T>' being compiled
1>        with
1>        [
1>            T=bool
1>        ]
1>main.cpp(43): message : see reference to class template instantiation 'DerivedClass<bool>' being compiled

Solution

  • How do I solve this?

    One way would be to make the function taking a bool by value take it by non-const reference and rvalue reference instead:

    virtual container_t<T> foo(const T& value1, const T& value2) const = 0;
    
    // instead of taking the `bool` by value:
    virtual container_t<bool> foo(bool& value1, const T& value2) const = 0;
    virtual container_t<bool> foo(bool&& value1, const T& value2) const = 0;
    

    ... and you'll then have to override both of them.