Генерируется ли объектный код для неиспользуемых методов класса шаблона? - PullRequest
11 голосов
/ 08 октября 2008

У меня есть шаблонный класс C ++, который создается с 3 различными параметрами типа. Есть метод, который класс должен иметь только для одного из этих типов, и который никогда не вызывается с двумя другими типами.

Будет ли объектный код для этого метода генерироваться трижды (для всех типов, для которых создается экземпляр шаблона), или объектный код генерируется только один раз (для типа, с которым он фактически используется)?

Ответы [ 3 ]

21 голосов
/ 08 октября 2008

Виртуальные функции-члены создаются при создании экземпляра шаблона класса, но не виртуальные функции-члены создаются только при их вызове.

Это описано в [temp.inst] в стандарте C ++ (в C ++ 11 это §14.7.1 / 10. В C ++ 14 это §14.7.1 / 11, а в C ++ 17 это §17.7.1 / 9. Выдержка из C ++ 17 ниже)

Реализация не должна неявно создавать экземпляр шаблона функции, шаблона переменной, члена шаблон, не виртуальная функция-член, класс-член, статический член данных шаблона класса или подстановка оператора constexpr if (9.4.1), если только такое создание не требуется

Также обратите внимание, что создание экземпляра шаблона класса возможно даже в том случае, если некоторые функции-члены не создаются для заданных параметров шаблона. Например:

template <class T>
class Xyzzy
{
public:
    void CallFoo() { t.foo(); }  // Invoke T::foo()
    void CallBar() { t.bar(); }  // Invoke T::bar()

private:
    T t;
};

class FooBar
{
public:
    void foo() { ... }
    void bar() { ... }
};

class BarOnly
{
public:
    void bar() { ... }
};

int main(int argc, const char** argv)
{
    Xyzzy<FooBar>  foobar;    // Xyzzy<FooBar> is instantiated
    Xyzzy<BarOnly> baronly;   // Xyzzy<BarOnly> is instantiated

    foobar.CallFoo();         // Calls FooBar::foo()
    foobar.CallBar();         // Calls FooBar::bar()

    baronly.CallBar();        // Calls BarOnly::bar()

    return 0;
}

Это верно, даже если Xyzzy :: CallFoo () не является экземпляром, потому что нет такой вещи, как BarOnly :: foo (). Эта функция часто используется в качестве инструмента метапрограммирования шаблонов.

Обратите внимание, однако, что «создание экземпляра» шаблона напрямую не связано с тем, сколько объектного кода генерируется. Это будет зависеть от вашей реализации компилятора / компоновщика.

2 голосов
/ 08 октября 2008

Я думаю, это зависит от компилятора и настроек. Например, я считаю, что MSVC6 сгенерировал все, но VS2005 нет. Спецификация говорит, что компилятор не должен, но в реальном мире это зависит от фактического компилятора (например, существует множество обходных путей для MSVC6). Компоновщик может удалить функции, на которые нет ссылок, если включен параметр / opt: ref (для VS эквивалентные параметры существуют для других компиляторов).

1 голос
/ 08 октября 2008

Обычно да.

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

Тем не менее, если рассматриваемые методы не виртуальные и никогда не вызываются, компоновщик может удалить их с помощью своих обычных функций удаления мертвого кода. Таким образом, сгенерированный (и скомпилированный) код не будет в конечном EXE.

Также это будет во многом зависеть от используемого компилятора C ++, потому что они не все одинаковые.

...