Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Overloading a C++ template class virtual function

Below is the code to recreate the problem I am having. Base class is a template class with the virtual function foo. foo has a default implementation that adds the passed in arguments.

SimpleDerived derives from Base, specializing it with std::string. SimpleDerived overloads the virtual Base<T>::foo() function. This class compiles fine and its foo outputs as expected when called in main.

#include <iostream>

template<class T>
struct Base
{
    virtual void foo(T val)
    {
        T local = val + val;    // THE OFFENDING LINE OF CODE
        std::cout << "Base" << std::endl;
    }   
};

struct SimpleDerived : public Base<std::string>
{
    virtual void foo(std::string val)
    {
        std::cout << "SimpleDerived" << std::endl;
    }
};

struct SimpleObject
{
    int value;
};

struct ComplexDerived : public Base<SimpleObject>
{
    virtual void foo(SimpleObject val)
    {
        std::cout << "ComplexDerived" << std::endl;
    }   
};

int main(void)
{
    Base<int> base;
    base.foo(2);

    SimpleDerived simpleDerived;
    simpleDerived.foo("hello world");

    SimpleObject object;
    ComplexDerived complexDerived;
    complexDerived.foo(object);

    return 0;
}

ComplexDerived derives from Base, specializing it with a custom struct SimpleObject. ComplexDerived overloads foo as well. However, this is the root of the problem. If I try to compile this I get:

quicktest.cpp: In member function ‘void Base<T>::foo(T) [with T = SimpleObject]’:
quicktest.cpp:47:1:   instantiated from here
quicktest.cpp:8:19: error: no match for ‘operator+’ in ‘val + val’

Obviously, there is no operator "+" for SimpleObject. But here is my confusion.. the compiler is being asked to implement Base<SimpleObject>::foo because this is what ComplexDerived inherits from. However, I never use or call Base<SimpleObject>::foo. So should the compiler be trying to generate this base class function?

like image 586
user2130260 Avatar asked Jun 14 '13 22:06

user2130260


1 Answers

Paragraph 14.7.1/10 of the C++11 Standard specifies:

An implementation shall not implicitly instantiate a function template, a member template, a non-virtual member function, a member class, or a static data member of a class template that does not require instantiation. It is unspecified whether or not an implementation implicitly instantiates a virtual member function of a class template if the virtual member function would not otherwise be instantiated. [...]

In other words, the behavior in this case is implementation-specific.

While in theory the compiler could figure out that the call to the base class's implementation of foo() won't ever be invoked (since the function call does not occur through a reference or pointer) and avoid instantiating it, this behavior is not mandated by the Standard.

like image 181
Andy Prowl Avatar answered Nov 10 '22 17:11

Andy Prowl