c++ G++ Linux在模板中显示了一个警告“使用不完整的类型”,而MSVC没有,我可以禁用此警告吗?

xqkwcwgp  于 2023-05-08  发布在  Linux
关注(0)|答案(1)|浏览(151)

我有两个文件,test.cppfoo.h。test.cpp:

#include <iostream>

class foo;

foo* fooInstance;
template<typename T> T bar() {

    return fooInstance->template barInternal<T>();

}

#include "foo.h"

int main() {

    fooInstance = new foo();
    std::cout << bar<int>();

    return 0;

}

foo.h:

class foo {

public:
    template<typename T> T barInternal() {

        return T(5);

    }

};

此代码在MSVC Windows上编译没有问题,在使用G++的Linux(Manjaro KDE)上编译和运行也没有问题,但是,它抛出了这个恼人的警告。

test.cpp: In function ‘T bar()’:
test.cpp:8:23: warning: invalid use of incomplete type ‘class foo’
8 |     return fooInstance->template barInternal<T>();
  |                       ^~
test.cpp:3:7: note: forward declaration of ‘class foo’
3 | class foo;
  |

为什么它会在G++上抛出一个警告,我如何才能摆脱这个警告(要么改变代码,要么以某种方式禁用这个警告,因为它看起来毫无用处)

mw3dktmi

mw3dktmi1#

这个警告似乎没有相应的警告标志,所以在GCC中禁用它的唯一方法是使用-w标志,它无条件地禁用所有警告,并且不能被-Wxxxx标志覆盖。
这个警告没有相应的警告标志的原因(我假设)是因为它实际上诊断了一个病态的情况:您的代码违反了标准。顺便说一句,这也是为什么Clang断然拒绝编译它的原因。
这里的相关规则是[temp.res.general]/6.4:
[...]如果出现以下情况,则程序是病态的,不需要诊断:[...]紧接着其定义的模板的假设示例化将是病态的,因为构造不依赖于模板参数[...]
在这种情况下,紧跟着bar定义的bar的假设示例化将是病态的,因为此时foo仍然不完整。即使您只打算在foo完成时示例化模板,根据标准,事实仍然是代码的格式不正确(不需要诊断)。
这可以通过向bar添加一个额外的模板参数来解决,该参数将默认为fooInstance

template<typename T, auto* p = fooInstance> T bar() {
    return p->template barInternal<T>();
}

现在,p是否指向不完整的类型取决于特定的p,因此不再满足“由于不依赖于模板参数的构造”的条件。
您仍然可以像当前一样调用bar<int>();由于默认模板参数,它意味着bar<int, fooInstance>()

相关问题