Question

Consider an example where a method is pure virtual, takes a parameter of a templated type (injected from an outer type), and that templated type is a local type (defined in a function body). This scenario causes a compile-time error under g++. Admittedly, this is quite a corner case, but it does originate from real code. Here's a compilable, reproducible example:

#include <cstdio>

template<typename T>
struct Outer
{
    struct InnerBase
    {
        virtual void foo(T const&) = 0;
        virtual void bar(T const&) {  };
    };

    struct InnerDerived : public InnerBase
    {
        void foo(T const&) override { std::printf("virtual call foo() worked\n"); }
        void bar(T const&) override { std::printf("virtual call bar() worked\n"); }
    };

    InnerBase* inner;
    Outer() : inner(new InnerDerived()) {  }
};


struct NonLocalStruct { };

int main()
{
    struct LocalStruct { };

    Outer<NonLocalStruct> a;
    Outer<LocalStruct>    b;

    a.inner->foo(NonLocalStruct());     // fine
    a.inner->bar(NonLocalStruct());     // fine
    b.inner->foo(LocalStruct());        // causes error
    b.inner->bar(LocalStruct());        // fine

    return 0;
}

Can someone explain why this causes a compile error? Why does it work with non-local types but not local ones? Why do non-pure virtual methods work but not pure ones?

I'm using g++ 4.8.1 with -std=c++11 (I've also tried this example in VS2010 and it compiles and runs without errors).

The exact error from g++ is:

test.cpp:8:16: error: 'void Outer::InnerBase::foo(const T&) [with T = main()::LocalStruct]', declared using local type 'const main()::LocalStruct', is used but never defined [-fpermissive]

Was it helpful?

Solution

My guess is that this is a g++ bug, that is somehow related to an old C++98 restriction on the use of local classes as template parameters

// C++98 Standard

14.3.1/2: A local type, a type with no linkage, an unnamed type or a type compounded from any of these types shall not be used as a template-argument for a template type-parameter.

In C++11, this restriction has been lifted. As you note, Visual Studio compiles this correctly, and so does Clang. As a work-around, adding the definition of the abstract function works with g++

template<typename T>
void Outer<T>::InnerBase::foo(T const&) {};

Live Example.

I think you should submit a bug report to g++.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top