Имеет ли смысл использовать встроенные ключевые слова в шаблонах?

119

Поскольку шаблоны определены в заголовках, и компилятор может определить, выгодно ли встраивание функции, имеет ли это смысл? Я слышал, что современные компиляторы лучше знают, когда встраивать функцию, и игнорируют inlineподсказки.


изменить: я хотел бы принять оба ответа, но это невозможно. Чтобы закрыть вопрос, я принимаю ответ Френеля , потому что он получил большинство голосов, и он формально прав, но, как я уже упоминал в комментариях, я считаю ответы Puppy и Компонента 10 правильными, с разных точек зрения. ,

Проблема в семантике C ++, которая не является строгой в случае inlineключевого слова и встраивания. Френель говорит: «пишите в строке, если вы это имеете в виду», но что на самом деле имеется в виду, inlineнеясно, поскольку оно эволюционировало от своего первоначального значения до директивы, которая, как говорит Puppy, « не дает компиляторам скучать по поводу нарушений ODR» .

доктор
источник

Ответы:

96

Это не имеет значения. И нет, не все шаблоны функций есть inlineпо умолчанию. Стандарт даже явно об этом говорит в явной специализации ([temp.expl.spec])

Иметь следующее:

a.cc

#include "tpl.h"

b.cc

#include "tpl.h"

tpl.h (взято из Explicit Specialization):

#ifndef TPL_H
#define TPL_H
template<class T> void f(T) {}
template<class T> inline T g(T) {}

template<> inline void f<>(int) {} // OK: inline
template<> int g<>(int) {} // error: not inline
#endif

Скомпилируйте это и вуаля:

g++ a.cc b.cc
/tmp/ccfWLeDX.o: In function `int g<int>(int)':
inlinexx2.cc:(.text+0x0): multiple definition of `int g<int>(int)'
/tmp/ccUa4K20.o:inlinexx.cc:(.text+0x0): first defined here
collect2: ld returned 1 exit status

Отсутствие inlineуказания, когда выполняется явное создание экземпляра, также может привести к проблемам.

Итак, вкратце : для не полностью специализированных шаблонов функций, то есть тех, которые содержат хотя бы один неизвестный тип, вы можете опустить inlineи не получать ошибки, но все же они не являются inline. Для полных специализаций, то есть тех, которые используют только известные типы, вы не можете пропустить его.

Предлагаемое эмпирическое правило : пишите, inlineесли вы серьезно, и просто будьте последовательны. Это заставляет вас меньше думать о том, стоит ли это делать, просто потому, что вы можете. (Это практическое правило соответствует шаблону C ++ Vandevoorde / Josuttis : The Complete Guide ).

Себастьян Мах
источник
2
Можно было написать, правда. Но это не подразумевает близости, даже если так кажется. Вандевурде и Йосаттис также точно заявляют об этом в шаблонах C ++: Полное руководство
Себастьян Мах
43
Явная специализация не является шаблоном.
Puppy
2
@DeadMG: Тем не менее, нормальная функция предпочтительнее полной специализации при поиске, поэтому, если они не являются ни шаблоном, ни не шаблоном, что тогда?
Себастьян Мах
13
Это неверный ответ. Явная специализация шаблона - это функция, а не шаблон. Эта функция не выполняется inlineтолько потому, что специализированный шаблон отмечен значком inline. Так что inlineо шаблоне совершенно неактуально. Должна быть эта функция inlineили нет, не имеет ничего общего с тем, что она генерируется с помощью специализации шаблона (и есть лучшие ответы, чем этот адрес, когда использовать inline). Ответ @Puppy ниже правильный, а этот - нет. Добавление inlineшаблона не имеет значения и clang-tidyфактически удалит его.
gnzlbg 09
6
Кроме того, в этом примере просто демонстрируются проблемы ODR для обычных функций (поведение здесь не имеет ничего общего с шаблонами). Для того, чтобы попытаться показать , что inlineне иметь никакого значения, пример должен охватывать случай явно специализирующийся template<> void f<>(int) {} без на inlineключевое слово. Но даже тогда изменение inlineспецификатора в шаблоне не имеет никакого значения, потому что отметьте вы шаблон inlineили нет, не имеет значения.
gnzlbg 09
34

Это не имеет значения. Все шаблоны уже есть, inlineне говоря уже о том, что с 2012 года inlineключевое слово используется только для того, чтобы компиляторы не жаловались на нарушения ODR. Вы абсолютно правы - ваш компилятор текущего поколения будет знать, что вставлять самостоятельно, и, вероятно, сможет это сделать даже между единицами перевода.

щенок
источник
11
Стандарт не утверждает, что все шаблоны являются встроенными.
Себастьян Мах
16
@phresnel: но шаблоны имеют ту же семантику, что и inlineфункции с метками (то есть несколько эквивалентных определений могут быть переданы компоновщику, который выберет одно). Это реальная функция inlineключевого слова , а не встраивание .
Ben Voigt
2
@BenVoigt: Я знаю, что такое ODR-значение inline. Может быть, взгляните на мой ответ ниже (или выше, в зависимости от выбранной сортировки). Для неспециализированных шаблонов вы, конечно, правы, но формально это не то.
Себастьян Мах
3
@DeadMG: В C ++ не требуется, чтобы шаблон функции был реализован в файле заголовка; его можно реализовать где угодно. Чтобы отразить это, я рекомендую отмечать inlineто, что должно быть встроенным. Обычно это не имеет значения, но в стандартном языке они не совпадают, и не все они встроены. Я принимаю вашу позицию по этому поводу: «Это неактуально», но по стандарту не все шаблоны встроены, только для вас, как пользователя C ++, они выглядят так, как будто.
Себастьян Мах
7
Ваш комментарий к принятому ответу о том, что явная специализация не является шаблоном (что , конечно, очевидно после того, как вам так сказали ...), возможно, является самым полезным на этой странице. Не могли бы вы добавить это и к своему ответу?
Кайл Стрэнд
6

Как вы предположили, inlineэто подсказка компилятору и не более того. Он может игнорировать это или, действительно, встроить функции, не отмеченные встроенными.

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

Маршалл Клайн объясняет это здесь лучше, чем я.

Компонент 10
источник
@Xeo: Раньше этого не было. Проверьте здесь: gcc.gnu.org/onlinedocs/gcc-4.0.4/gcc/ ... Я полагаю, что это изменилось в последнее время, поэтому я говорил в прошедшем времени.
Компонент 10 10
2
@Xeo: Можете ли вы указать мне на часть Стандарта, в которой говорится, что шаблоны функций всегда встроены? Потому что это не так.
Себастьян Мах
@phresnel: Интересно, могу поклясться, что читал об этом в стандарте. Возможно, я перепутал это с тем, что шаблоны функций не подлежат ODR ( §14.5.5.1 p7 & p8). Моя беда, я удалил не тот комментарий.
Xeo
@Component 10 Почему вы думаете, что это плохой способ
Капил