3

考虑一个示例,其中方法是纯虚拟的,采用模板类型的参数(从外部类型注入),并且该模板类型是本地类型(在函数体中定义)。这种情况会导致 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() 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;
}

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

我正在使用带有 -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'声明,已使用但从未定义 [-fpermissive]

4

1 回答 1

1

我的猜测是这是一个 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++提交错误报告。

于 2013-09-25T06:36:26.607 回答