Предупреждение компилятора в базовом классе шаблона C ++ - PullRequest
12 голосов
/ 16 июня 2010

Я получаю предупреждение компилятора, которого я не понимаю в этом контексте.Когда я компилирую «Child.cpp» из следующего кода.(Не удивляйтесь: я сократил свои классные объявления до минимума, так что содержание не будет иметь особого смысла, но вы увидите проблему быстрее).Я получаю предупреждение с Visual Studio 2003 и Visual 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 ::Отмена ': локальная функция без ссылки была удалена с помощью [T = int]

... при компиляции "Child.cpp".Я не понимаю этого, потому что это публичная функция, и компилятор не может знать, буду ли я позже ссылаться на этот метод или нет.И, в конце концов, я ссылаюсь на этот метод, потому что я вызываю его в 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;
}

Мне помогли ответы, которые я знаю, но я не думаю, что на этот вопрос дан полный ответ.

Ответы [ 7 ]

4 голосов
/ 09 января 2012

Я не вижу правильного ответа где-либо здесь: если у вас есть чистый виртуальный метод в шаблонном классе, Visual Studio неправильно сообщает об этом предупреждении. Другие компиляторы, такие как gcc и clang, в этом случае не отображают это предупреждение.

Чистые виртуальные методы в шаблонных или не шаблонных классах вполне разумны, и часто это хорошая идея - объявление метода чисто виртуальным заставляет вас применять его в производных классах.

Я нигде не нашел ссылку на это как на ошибку - я не в программе Microsoft для разработчиков, возможно, кто-то, кто мог бы написать эту ошибку?

2 голосов
/ 25 июня 2010

Я не думаю, что предупреждение является преднамеренным.Компилятор ошибочно полагает, что эта функция local для единицы перевода, но эта функция вовсе не такова.Вы используете сгенерированную функцию в другой единице перевода из main, поэтому используется функция .Разные способы заставить предупреждение исчезнуть, похоже, что это разные способы обхода пути ошибки в компиляторе.

Разница в отношении virtual заключается в том, что virtual функции могут быть созданыдаже без их использования.Это происходит, когда их класс обычно неявно создается.Стандарт объявляет это действительным (выделено мной)

Реализация не должна неявно создавать экземпляр шаблона функции, шаблона элемента, не виртуальной функции-члена, класса-члена или статического члена данныхШаблон класса, который не требует создания экземпляров. Не определено, будет ли реализация неявно создавать экземпляр виртуальной функции-члена шаблона класса, если в противном случае функция виртуального члена не будет создаваться.неявные экземпляры этой такой же виртуальной функции.Тот, что в Child.h, был сделан без всякого использования, и поэтому компилятор считает, что функция бесполезна.Но поскольку та же самая функция используется в другом месте (в main.cpp), это предупреждение явно не в порядке.

0 голосов
/ 16 января 2016

Предупреждение просто говорит о том, что компоновщик не может видеть использование функции.

Если вы хотите «сказать» компоновщику, чтобы избежать предупреждения, вы можете обмануть компоновщика, чтобы «подумать», что он используется.

Например:

void MyLinkerThinkNotUsedFunction
{
}

void* Foo = (void*)MyLinkerThinkNotUsedFunction;

будет достаточно, чтобы избежать каких-либо предупреждений C4505 о функции MyLinkerThinkNotUsedFunction.

0 голосов
/ 05 июня 2015

В Visual Studio 2010 это предупреждение исчезает, если вы определяете конструктор для производного класса (вашего дочернего класса).

0 голосов
/ 16 июня 2010

Шаблоны создаются перед генерацией кода.Это означает, что компилятор должен знать определенный класс, используемый в шаблоне, чтобы иметь возможность генерировать код для этого шаблона.Таким образом, когда вы определяете свой метод класса шаблона в отдельном модуле, его определение неизвестно во время создания шаблона.

Скорее всего, предупреждение означает, что код для AbstractClass<T>::Cancel не генерируется в единице, которую вы использовали для определения AbstractClass<T>::Cancel.Методы класса шаблона генерируются только после того, как они используются (т.е. ссылаются, вызываются), в отличие от обычного кода метода, который генерируется, когда он встречается.

Если вы попытаетесь вызвать AbstractClass<T>::Cancel из функциито есть AbstractClass.cpp, где определено Cancel, предупреждение должно исчезнуть.

0 голосов
/ 16 июня 2010

Создание шаблона функции виртуальным не разрешено. Смотрите вопрос переполнения стека Делает ли специализацию шаблона функции виртуальной законной?

0 голосов
/ 16 июня 2010

Код в обычных не шаблонных методах класса компилируется, когда компилятор встречает код для метода.

Для шаблонных классов это не так. Код находится в заголовке, поэтому, если компилятор будет компилировать его каждый раз, когда встречает код, это будет означать, что этот метод компилируется снова и снова, даже если он не вызывается вашим кодом. Предположим, что child.h включен в 1000 других файлов. Вы хотите, чтобы компилятор компилировал метод Cancel 1000 раз или только когда фактически вызывается метод Cancel?

child.cpp включает child.h, но не вызывает метод Cancel. Поэтому Cancel не компилируется (хотя я нахожу странным, что вы получаете предупреждение за это).

main.cpp также включает child.h, и на этот раз он вызывает метод Cancel, который является сигналом для компилятора для компиляции метода. Наконец, компоновщик найдет все скомпилированные экземпляры метода Cancel и объединит их.

...