Встроенный классификатор проистекает из прототипа или определения?

Я не совсем уверен в этом. Скажем, у меня есть три файла:

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 в обоих местах.