函数模板中使用的类的前向声明未编译

时间:2018-07-23 10:21:28

标签: c++ templates gcc forward-declaration

我有以下代码,它们不是用gcc编译的,而是可以用MSVC完美编译的。

class B;

class A
{
    B *_parent;

public:

    template <typename T>
    void Do(T val)
    {
        _parent->DoB(val);
    }

    A(B *parent)
        :   _parent(parent)
    {
    }
};

class B : public A
{
public:

    B()
        : A(nullptr)
    {
    }

    void DoB(int val)
    {
        cout << val << endl;
    }
};

int main() {
    B b;
    A a(&b);
    a.Do(10);
    return 0;
}

编译错误如下:

prog.cpp: In member function ‘void A::Do(T)’:
prog.cpp:15:10: error: invalid use of incomplete type ‘class B’
   _parent->DoB(val);
          ^~
prog.cpp:4:7: note: forward declaration of ‘class B’
 class B;
       ^

根据类似的帖子,由于该标准的14.6.9段,gcc的行为是正确的。但这是违反直觉的,因为模板只能在使用的地方实例化。唯一的用法是在定义了所有类之后发生。

我的问题是此问题的解决方法是什么?因为在这种情况下使用成员模板非常方便。也许问题出在架构或其他方面?

2 个答案:

答案 0 :(得分:2)

您可以声明A中依赖B的部分,但是以后再定义。声明看起来像这样

class B;

class A
{
    B *_parent;

    public:
        template <typename T> void Do(T val); /* (see below) */
        A(B *parent) :   _parent(parent) {}
};

然后是B

的定义
class B : public A { /* As before. */ };

最后定义缺失的部分

template <typename T> void A::Do(T val)
{
    _parent->DoB(val); /* Fine, B is known. */
}

作为附带说明,原始代码仅使用gcc 8进行了警告编译。

答案 1 :(得分:1)

您可以添加额外的图层:

class A
{
    B *_parent;

private:
    template <typename TB, typename T>
    static void CallDoB(TB* b, T&& val) {
        b->DoB(std::forward<T>(val));
    }
public:

    template <typename T>
    void Do(T val)
    {
        CallDoB(_parent, val);
    }

    A(B *parent) : _parent(parent) {}
};

现在b->依赖于模板,并被推迟到实际实例化为止。