Встроенный классификатор проистекает из прототипа или определения?
Я не совсем уверен в этом. Скажем, у меня есть три файла:
foo.h
#include <iostream>
inline void foo();
void foo()
{
std::cout << "Foo" << std::endl;
}
foo.cpp:
#include "foo.h"
void baz();
int main()
{
baz();
foo();
}
bar.cpp
#include "foo.h"
void baz()
{
foo();
}
Теперь определение foo будет скомпилировано в оба блока компиляции foo.o и bar.o. Если я правильно ее понимаю, встроенные функции будут избегать объединения ссылок. g++ скомпилирован и связывает это просто отлично, но с clang++ 2.8 я получаю эту ошибку:
/tmp/cc-7RdmYP.o: In function `foo()':
bar.cpp:(.text+0x50): multiple definition of `foo()'
/tmp/cc-LW3id3.o:foo.cpp:(.text+0x50): first defined here
collect2: ld returned 1 exit status
Кажется, что clang++ не видит void foo()
как встроенную функцию. Однако он отлично работает, когда я добавляю встроенное определение.
Нужно ли мне добавлять inline в void foo()
, чтобы увидеть его как встроенную функцию, или это ошибка clang++?
Ответы
Ответ 1
С++ 0X черновик N3225 говорит в 7.1.2 Function specifiers
:
-
clause 2: A function declaration with an inline specifier declares an inline function
-
clause 4: An inline function shall be defined in every translation unit in which it is odr-used and shall have exactly the same definition in every case.
Итак, для меня это похоже, что gcc прав и не прав, но есть еще (тонкий) шанс, что вещи были (есть?) разными в С++ 03..
Ответ 2
Скорее всего, ваш clang использует встроенную семантику C99. В C99, если одна из ваших функций не использует "встроенный" или не включает "extern", тогда определение является "внешним определением", которое может появляться только один раз в программе. См. inline в C99.
В С++ ваша программа в порядке. В Clang SVN эта ошибка исправлена, и ваша программа должна работать нормально.
Ответ 3
Я считаю, что цель стандарта всегда заключалась в том, чтобы позволить функции inline
иметь хотя бы одно объявление, включая спецификатор inline
, но была некоторая неопределенность в отношении того, когда было слишком поздно добавлять первая inline
декларация. Было ли это после слишком позднего определения или после первого вызова?
Мое рассуждение о том, что это два раза, сначала примеры из 7.1.1, хотя и не нормативные и в основном о спецификаторах класса хранения, свидетельствуют о том, что inline
не требуется для каждого объявления.
Во-вторых, этот отчет о дефекте DR 317 с 2001 года (проголосовал в 2005 году), который добавляет: "Если определение функции появляется в переводе блок до его первого объявления как встроенный, программа плохо сформирована". предложение. Из беседы ясно, что было сделано предположение, что inline
не требуется для каждого объявления, особенно в случае функции-члена, явно определенной inline
, но вне класса класса, где исходное объявление не имеет Явный inline
.
(Этот отчет о дефекте также содержит мою мантру, что inline
является "более чем намеком".)
Конечно, как только функция с внешней связью является встроенной функцией из-за одной или нескольких деклараций, включая спецификатор inline
в одной единицы перевода, она должна быть объявлена inline
во всех единицах трансляции в соответствии с остальной частью пункт 7.1.2/4.
В примере в вопросе я считаю, что намерение состоит в том, что foo
является встроенной функцией и что он действительный код, хотя нормативный текст стандарта кажется мне менее понятным, чем это могло бы быть.
Ответ 4
Вы должны использовать inline
в обоих местах.