模板、内部结构、局部类型和纯虚函数,天哪



考虑一个示例,其中一种方法是纯虚拟的,采用模板化类型的参数(从外部类型注入),并且该模板化类型是局部类型(在函数体中定义)。此方案会导致 g++ 下的编译时错误。诚然,这是一个相当极端的情况,但它确实起源于真实的代码。下面是一个可编译、可重现的示例:

#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() workedn"); }
        void bar(T const&) override { std::printf("virtual call bar() workedn"); }
    };
    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;
}

有人可以解释为什么这会导致编译错误吗?为什么它适用于非本地类型而不是本地类型?为什么非纯虚拟方法有效,而纯虚拟方法无效?

我正在使用带有 -std=c++11 的 g++ 4.8.1(我也在 VS2010 中尝试过这个例子,它的编译和运行没有错误)。

g++ 的确切错误是:

test.cpp:8:16: 错误: 'void Outer::InnerBase::foo(const T&) [with T = main()::LocalStruct]',使用本地类型'const main()::LocalStruct'声明,使用但从未定义[-fallowive]

我的猜测是这是一个 g++ 错误,与旧的 C++98 限制使用本地类作为模板参数有关

C++98 标准

14.3.1/2:本地类型、无链接类型、未命名类型或由任何这些类型复合的类型不得用作模板类型参数的模板参数。

在C++11中,这一限制已被取消。正如你所注意到的,Visual Studio正确地编译了它,Clang也是如此。作为一种解决方法,添加抽象函数的定义适用于 g++

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

活生生的例子

我认为您应该向 g++ 提交错误报告

最新更新