2011-02-07 4 views
11

Я не совсем уверен в этом в стандартах. Скажем, у меня есть три файла, как это:Встроенные отборочные линии от прототипа или определения?

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 ++ компилируется и ссылки это просто отлично, но с грохотом ++ 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 

Кажется, что лязг ++ не видит void foo() как встраиваются функции. Однако он отлично работает, когда я добавляю встроенное определение.

Должен ли я добавить встроенную строку в void foo(), чтобы увидеть ее как встроенную функцию, или это ошибка clang ++?

+0

Я думаю, вы имеете в виду «определение», а не «объявление». – Maxpm

+0

Ах, да, я, как правило, смешиваю эти ...;) – Maister

+0

Это интересный вопрос. –

ответ

2

C++ 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 является правильным & лязг неправильно, но все еще есть (тонкий) шанс, что вещи были (есть?) разные в C++ 03 ..

+1

С ++ 03 формулировка идентична, за исключением того, что «odr-used» был просто «использован». – aschepler

+0

@Eugen: предложение 1 кажется довольно интересным * Функции-спецификаторы могут использоваться ** только ** в объявлениях функций * (мой акцент). –

+0

Я думаю, что Бен Фойгт здесь правильно (не думал об этом при цитировании изначально). Определение также является декларацией. В стандарте говорится: «Объявление объекта, однако, также является определением, если оно не содержит спецификатор extern и не имеет инициализатора.» – sstn

0

Вы должны использовать inline в обоих местах.

+4

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

+0

Возможно, сейчас я запутываю вещи, но в стандарте 1998 года сказано: «В программе может быть более одного определения [...], встроенной функции с внешней связью, [...] в программе, при условии, что каждое определение появляется в другом единица перевода, [...] "(раздел 3.2, раздел 5) – sstn

+0

7.1.2, раздел 1 (1998 снова ...) говорит:« Спецификаторы функций могут использоваться только в объявлениях функций ». – sstn

1

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

Мое рассуждение для этого состоит из двух раз, сначала примеры из 7.1.1, хотя и не нормативные и в основном касающиеся спецификаторов класса хранения, свидетельствуют о том, что inline не требуется для каждого объявления.

Во-вторых, этот отчет о дефектах DR 317 с 2001 года (проголосовал в 2005 году), который добавляет: «Если определение функции появляется в блоке перевода до его первого объявления как встроенное, программа плохо сформирована». предложение. Из беседы ясно, что inline не требуется для каждого объявления, особенно в случае функции-члена, определенной явно inline, но вне класса класса, в которой оригинальная декларация не имела явного inline.

(В этом отчете о дефектах также содержится моя мантра, что inline является «более чем намеком».)

Конечно, как только функция с внешним связыванием является встроенной функцией из-за одного или несколько деклараций включая inline спецификатора в одном блоке перевода она должна быть объявлена ​​inline во всех единицах трансляции в соответствии с остальной частью пункт 7.1.2/4.

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

4

Коэффициенты в том, что ваш clang использует встроенную семантику C99. В C99, если одна из ваших функций не использует «встроенный» или не включает «extern», тогда определение является «внешним определением», которое может появляться только один раз в программе. См. inline in C99.

В C++ ваша программа в порядке. В Clang SVN эта ошибка исправлена, и ваша программа должна работать нормально.

Смежные вопросы