Разрешено ли компилятору игнорировать inline в случае специализации шаблона? - PullRequest
5 голосов
/ 19 ноября 2009

Допустим, у вас есть простая шаблонная функция (не член класса для простоты) со специализацией типа в том же файле .h ...

template <class TYPE>
void    some_function(TYPE& val)
{
    // some generic implementation
}

template <>
inline void some_function<int>(int& val)
{
    // some int specific implementation
}

Если вы явно не направите свой компилятор на inline специализацию (inline ключевое слово), вы получите ошибку компоновки, если файл .h включен более одного раза (по крайней мере, я это сделал в Visual C ++ 2008).
Все мы знаем, что inline - это всего лишь предложение для компилятора, которое он может игнорировать. В этом конкретном случае разрешено ли компилятору игнорировать это предложение и позволить компоновщику выйти из строя?

Ответы [ 5 ]

7 голосов
/ 19 ноября 2009

Если вы не используете inline, то одна и та же функция компилируется с extern связью в несколько .obj файлов, что заставляет компоновщик выдавать ошибку дублирующегося символа.

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

5 голосов
/ 19 ноября 2009

Вы неправильно понимаете значение часто упоминаемой возможности "игнорировать inline".

Ни одному компилятору не разрешается игнорировать спецификатор inline, используемый в объявлении функции, и последствия, которые этот спецификатор имеет для правила определения одного (ODR).

Когда кто-то говорит, что компилятору разрешено "игнорировать inline", это означает лишь то, что компиляторам не требуется фактически вставлять вызовы для рассматриваемой функции. «Игнорировать встроенный» означает генерировать обычный (не встроенный) вызов функции для встроенной функции.

В любом случае, даже если компилятор решил всегда генерировать обычные вызовы встроенной функции (т. Е. Всегда «игнорировать встроенную»), он все равно должен обрабатывать функцию как встроенную для целей ODR. Как компилятор собирается это делать - это проблема компилятора. Вы не должны беспокоиться об этом.

В исходном примере не должно быть ошибок компоновщика.

1 голос
/ 19 ноября 2009

Это определено стандартом, и компилятор полностью соответствует в этом отношении, судя по всему. Связь - это все, что вам нужно. Неявные экземпляры шаблонов имеют «специальную» связь, как встроенные функции. Существует также статический (ключевое слово), который устарел в пользу анонимных пространств имен:

namespace {
    …declarations…
}

Так что да, эта специализация (в вашем примере) имеет ту же связь, что и:

void some_other_function(int& val) {
    // some int specific implementation
}

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

0 голосов
/ 19 ноября 2009

То, что вы на самом деле видите, это то, что у правила единого определения (ODR) есть особый случай для встроенных функций, в котором у каждого TU может быть определение. Если функция, такая как ваша явная специализация int, не является встроенной, вы получите несколько ошибок определения во время ссылки. Такие встроенные функции все еще имеют внешнюю связь. Шаблоны функций: , шаблоны и, следовательно, следуют другим правилам. Учреждения / специализации шаблона функции: функции .

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

Заголовочный файл:

template<class TYPE>
void some_function(TYPE& val) {
  // some generic implementation
}

template<>
void some_function<int>(int& val);

Файл реализации (.cpp):

template<>
void some_function<int>(int& val) {
  // some int specific implementation
}
0 голосов
/ 19 ноября 2009

Я полагаю, что вы можете явно объявить метод как extern, а затем поместить специализацию в .cpp. Я пробовал нечто подобное в прошлой жизни с GCC, но я не помню точных деталей того, как это работало. В журнале MSDN есть статья на эту , которая может помочь.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...