C++ 处的编译器警告模板基类

发布于 2024-09-06 00:47:06 字数 2603 浏览 0 评论 0原文

我收到编译器警告,我在该上下文中不理解。当我从以下代码编译“Child.cpp”时。 (不要奇怪:我将类声明剥离到最低限度,因此内容没有多大意义,但您会更快地看到问题)。我收到 Visual Studio 2003Visual Studio 2008 处于最高警告级别。


代码

AbstractClass.h:

#include <iostream>

template<typename T>
class AbstractClass
{
    public:
        virtual void Cancel(); // { std::cout << "Abstract Cancel" << std::endl; };
        virtual void Process() = 0;
};

// Outside definition. If I comment out this and take the inline
// definition like above (currently commented out), I don't get
// a compiler warning.
template<typename T>
void AbstractClass<T>::Cancel()
{
    std::cout << "Abstract Cancel" << std::endl;
}

Child.h:

#include "AbstractClass.h"

class Child : public AbstractClass<int>
{
    public:
        virtual void Process();
};

Child.cpp:

#include "Child.h"
#include <iostream>

void Child::Process()
{
    std::cout << "Process" << std::endl;
}

警告

类“Child”派生自“AbstractClass”。在“AbstractClass”中有公共方法“AbstractClass::Cancel()”。如果我在类主体之外定义该方法(就像您看到的代码中一样),我会收到编译器警告...

AbstractClass.h(7):警告 C4505:“AbstractClass::Cancel”:未引用的本地函数已被删除 与 [T=int]

...当我编译“Child.cpp”时。我不明白这一点,因为这是一个 public 函数,编译器无法知道我以后是否引用了这个方法。最后,我引用了这个方法,因为我在 main.cpp 中调用它,尽管有这个编译器警告,但如果我编译并链接所有文件并执行程序,这个方法就会起作用:

//main.cpp
#include <iostream>
#include "Child.h"

int main()
{
    Child child;
    child.Cancel();  // Works, despite the warning
}

如果我确实将 Cancel() 函数定义为内联(您将其视为 AbstractClass.h 中的注释代码),那么我不会收到编译器警告。当然,我的程序可以工作,但我想理解这个警告,还是这只是一个编译器错误?

此外,如果不将 AbsctractClass 实现为模板类(在本例中仅用于测试目的),我也不会收到编译器警告...?


如果我创建一个非虚拟函数,我不会收到该非虚拟函数的编译警告,但到目前为止的所有答案都不包含虚拟内容。试试这个:

template<typename T>
class AbstractClass
{
    public:
        virtual void Cancel(); // { std::cout << "Abstract Cancel" << std::endl; };
        virtual void Process() = 0;
        void NonVirtualFunction();
};

//...

template<typename T>
void AbstractClass<T>::NonVirtualFunction()
{
    std::cout << "NonVirtualFunction" << std::endl;
}

已知的答案对我有帮助,但我认为问题没有得到完全解答。

I get a compiler warning, that I don't understand in that context. When I compile the "Child.cpp" from the following code. (Don't wonder: I stripped off my class declarations to the bare minimum, so the content will not make much sense, but you will see the problem quicker). I get the warning with Visual Studio 2003 and Visual Studio 2008 on the highest warning level.


The code

AbstractClass.h:

#include <iostream>

template<typename T>
class AbstractClass
{
    public:
        virtual void Cancel(); // { std::cout << "Abstract Cancel" << std::endl; };
        virtual void Process() = 0;
};

// Outside definition. If I comment out this and take the inline
// definition like above (currently commented out), I don't get
// a compiler warning.
template<typename T>
void AbstractClass<T>::Cancel()
{
    std::cout << "Abstract Cancel" << std::endl;
}

Child.h:

#include "AbstractClass.h"

class Child : public AbstractClass<int>
{
    public:
        virtual void Process();
};

Child.cpp:

#include "Child.h"
#include <iostream>

void Child::Process()
{
    std::cout << "Process" << std::endl;
}

The warning

The class "Child" is derived from "AbstractClass". In "AbstractClass" there's the public method "AbstractClass::Cancel()". If I define the method outside of the class body (like in the code you see), I get the compiler warning...

AbstractClass.h(7) : warning C4505: 'AbstractClass::Cancel' : unreferenced local function has been removed
with [T=int]

...when I compile "Child.cpp". I do not understand this, because this is a public function, and the compiler can't know if I later reference this method or not. And, in the end, I reference this method, because I call it in main.cpp and despite this compiler warning, this method works if I compile and link all files and execute the program:

//main.cpp
#include <iostream>
#include "Child.h"

int main()
{
    Child child;
    child.Cancel();  // Works, despite the warning
}

If I do define the Cancel() function as inline (you see it as out commented code in AbstractClass.h), then I don't get the compiler warning. Of course my program works, but I want to understand this warning or is this just a compiler mistake?

Furthermore, if do not implement AbsctractClass as a template class (just for a test purpose in this case) I also don't get the compiler warning...?


If I make a non-virtual function, I don't get the compile warning for that non-virtual function, but all answers up to now don't comprise the virtual stuff. Try this:

template<typename T>
class AbstractClass
{
    public:
        virtual void Cancel(); // { std::cout << "Abstract Cancel" << std::endl; };
        virtual void Process() = 0;
        void NonVirtualFunction();
};

//...

template<typename T>
void AbstractClass<T>::NonVirtualFunction()
{
    std::cout << "NonVirtualFunction" << std::endl;
}

The answers up to know helped me, but I don't think that the question is fully answered.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

画骨成沙 2024-09-13 00:47:06

我在这里没有看到正确的答案:如果模板类中有纯虚拟方法,Visual Studio 会错误报告此警告。在这种情况下,其他编译器(例如 gcc 和 clang)似乎不会报告此警告。

模板化或非模板化类中的纯虚拟方法是完全合理的,而且通常是一个好主意 - 将方法声明为纯虚拟会迫使您在派生类中实现它。

我没有在任何地方找到对此错误的引用 - 我不在 Microsoft 开发人员计划中,也许有人可以提交此错误?

I don't see the correct answer anywhere here: if you have a pure virtual method in a templated class, Visual Studio incorrectly reports this warning. Other compilers, like gcc and clang, do not appear to report this warning in this case.

Pure virtual methods in templated or non-templated classes are perfectly reasonable, and often a good idea - declaring the method as pure virtual forces you to implement it in derived classes.

I didn't find a reference to this anywhere as a bug - I'm not in a Microsoft developer program, perhaps someone who is could file this bug?

冰魂雪魄 2024-09-13 00:47:06

我不认为这个警告是故意的。编译器错误地认为该函数对于翻译单元来说是本地,但该函数根本不是这样。您在 main 的另一个翻译单元中使用生成的函数,因此使用了该函数。您想出的使警告消失的不同方法似乎是解决编译器中的错误路径的不同方法。

virtual 的区别在于virtual 函数即使不使用它们也可以被实例化。当他们的类被隐式实例化时通常会发生这种情况。该标准声明有效(我强调)

实现不得隐式实例化函数模板、成员模板、非虚拟模板
不需要实例化的成员函数、成员类或类模板的静态数据成员。 如果虚拟成员函数不会被实例化,则实现是否隐式实例化类模板的虚拟成员函数是未指定的。

在这种情况下,有两个相同的隐式实例化 虚函数。 Child.h 中的函数没有任何用处,因此编译器认为该函数是无用的。但由于相同的函数在其他地方(在 main.cpp 中)使用,该警告显然是不一致的。

I don't think that warning is intentional. The compiler mistakenly belives that the function is local to the translation unit, but the function isn't such at all. You use the generated function in the other translation unit from main, thus the function is used. The different ways you figured out to make the warning disappear just seem to be different ways to work around the buggy path in the compiler.

The difference with regard to virtual is that virtual functions can be instantiated even without a use of them. This happens when their class was implicitly instantiated usually. The Standard declares that valid (emphasis by me)

An implementation shall not implicitly instantiate a function template, a member template, a non-virtual
member function, a member class or a static data member of a class template that does not require instantiation. It is unspecified whether or not an implementation implicitly instantiates a virtual member function of a class template if the virtual member function would not otherwise be instantiated.

In this case there are two implicit instantiations of that same virtual function. The one in Child.h was done without any use, and thus the compiler thinks the function is useless. But as that same function is used elsewhere (in main.cpp), that warning is clearly at odds.

尽揽少女心 2024-09-13 00:47:06

该警告只是表明链接器无法看到该函数的任何用法。

如果您想“告诉”链接器避免警告,您可以欺骗链接器“认为”它正在使用。

例如:

void MyLinkerThinkNotUsedFunction
{
}

void* Foo = (void*)MyLinkerThinkNotUsedFunction;

足以避免函数 MyLinkerThinkNotUsedFunction 上出现任何警告 C4505。

The warning simply says that the linker cannot see any usage of the function.

If you want to"tell" the linker to avoid the warning you can fool the linker into "think" it is in use.

For example:

void MyLinkerThinkNotUsedFunction
{
}

void* Foo = (void*)MyLinkerThinkNotUsedFunction;

will suffice to avoid any warning C4505 on the function MyLinkerThinkNotUsedFunction.

只涨不跌 2024-09-13 00:47:06

当编译器遇到该方法的代码时,将编译普通非模板化类方法中的代码。

对于模板类来说这是不同的。代码位于标头中,因此如果编译器每次遇到代码时都会对其进行编译,则意味着该方法会被一遍又一遍地编译,即使您的代码没有调用它。
假设 child.h 包含在 1000 个其他文件中。您希望编译器编译 Cancel 方法 1000 次,还是仅在实际调用 Cancel 时编译?

child.cpp 包含 child.h,但不调用 Cancel 方法。因此 Cancel 不会被编译(尽管我觉得很奇怪你会收到这样的警告)。

main.cpp中还包含了child.h,这次它调用了Cancel方法,这是编译器编译该方法的信号。最后,链接器将找到 Cancel 方法的所有已编译实例并合并它们。

The code in normal, non-templated class methods is compiled when the compiler encounters the code for the method.

For templated classes this is different. The code is in the header so if the compiler would compile it every time it encounters the code, it would mean that this method is compiled over and over again, even if it is not called by your code.
Suppose that child.h is include in 1000 other files. Do you want the compiler to compile the Cancel method 1000 times, or only when Cancel is actually called?

child.cpp includes child.h, but does not call the Cancel method. Therefore Cancel is not compiled (although I find it strange that you get a warning for this).

main.cpp also includes child.h, and this time it calls the Cancel method, which is a signal for the compiler to compile the method. Finally, the linker will find all compiled instantiations of the Cancel method and merge them.

我乃一代侩神 2024-09-13 00:47:06

在 Visual Studio 2010 中,如果您为派生类(您的子类)定义构造函数,此警告就会消失。

In Visual Studio 2010 this warning disappears if you define a constructor for the derived class (your child class).

对你再特殊 2024-09-13 00:47:06

模板在代码生成之前实例化。这意味着编译器需要知道模板中使用的特定类才能为该模板生成代码。因此,当您在单独的单元中定义模板类方法时,其定义在模板实例化时是未知的。

该警告很可能意味着 AbstractClass::Cancel 的代码未在您用于 AbstractClass::Cancel 定义的单元中生成。模板类方法仅在使用(即引用、调用)后才生成,这与普通方法代码相反,普通方法代码一旦遇到就生成。

如果您尝试从定义了 Cancel 的 ie AbstractClass.cpp 中的函数调用 AbstractClass::Cancel,则应出现警告离开。

Templates are instantiated before code generation. This means that compiler needs to know the specific class used in a template to be able to generate code for that template. So, when you define your template class method in a separate unit, its definition is unknown at the time of template instantiation.

The warning most likely means that the code for AbstractClass<T>::Cancel is not generated in the unit you used for AbstractClass<T>::Cancel definition. Template class methods are only generated once they're used (i.e. referenced, called), as opposed to normal method code, which is generated once it's encountered.

If you try to call AbstractClass<T>::Cancel from a function in i.e. AbstractClass.cpp, where Cancel is defined, the warning should go away.

画尸师 2024-09-13 00:47:06

将函数模板设为虚拟是不合法的。请参阅堆栈溢出问题
制作函数模板专业化虚拟合法吗?

Making a function template virtual is not legal. See Stack Overflow question
Is making a function template specialization virtual legal?.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文