Что означает подчиняться ODR в случае встроенных функций и функций constexpr?

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

inline void foo() {
    return;
}

inline void foo() {
    return;
}

int main() {
    foo();
};

ошибка: переопределение void foo (),
и

constexpr int foo() {
    return 1;
}

constexpr int foo() {
    return 1;
}

int main() {
    constexpr x = foo();
}; 

ошибка: переопределение 'constexpr int foo ()'

Так что же именно означает, что constexpr и встроенная функция могут подчиняться ODR?


person senfen    schedule 26.03.2015    source источник
comment
Это означает, что у вас может быть несколько определений для них в разных единицах перевода.   -  person T.C.    schedule 26.03.2015


Ответы (3)


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

Это относится к встроенным функциям в разных единицах перевода. В вашем примере они оба находятся в одной единице перевода.

Это описано в проекте стандарта C ++ 3.2 Одно правило определения [basic.def.odr], которое гласит:

Может быть несколько определений типа класса (пункт 9), типа перечисления (7.2), встроенной функции с внешней связью (7.1.2), шаблона класса (пункт 14), нестатического шаблон функции (14.5.6), статический член данных шаблона класса (14.5.1.3), функция-член шаблона класса (14.5.1.1) или специализация шаблона, для которой не указаны некоторые параметры шаблона (14.7, 14.5.5 ) в программе при условии, что каждое определение появляется в разных единицах перевода, и при условии, что определения удовлетворяют следующим требованиям. Если такая сущность с именем D определена более чем в одной единице перевода, то

и включает в себя следующий пункт:

  • каждое определение D должно состоять из одной и той же последовательности токенов; и
person Shafik Yaghmour    schedule 26.03.2015
comment
Хорошее объяснение. - person Syfu_H; 10.04.2019

Вы многократно определяете функции в одной единице перевода. Это всегда запрещено:

Ни одна единица перевода не должна содержать более одного определения любой переменной, функции, типа класса, типа перечисления или шаблона. (С ++ 11 3.2 / 1)

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

Встроенная функция должна быть определена в каждой единице трансляции, в которой она используется odr. (С ++ 11 3.2 / 3)

Для "обычных" (не встроенных, не constexpr, не шаблонных и т. Д.) Функций с внешними (нестатическими) функциями связывания это обычно (не требует диагностики) приводит к ошибке компоновщика.

Каждая программа должна содержать ровно одно определение каждой не встроенной функции или переменной, которая используется odr в этой программе; диагностика не требуется. (С ++ 11 3.2 / 3)

Подводить итоги:

  • Никогда не определяйте что-либо несколько раз в одной единице перевода (которая является файлом .cpp и всеми прямо или косвенно включенными заголовками).
  • You may put a certain number of things into header files, where they will be included once in several different translation units, for example:
    • inline functions
    • class типов и templates
    • static элементы данных class template.
person gha.st    schedule 26.03.2015
comment
Хорошее объяснение. - person Syfu_H; 10.04.2019

Если у вас есть:

file1.cpp:

inline void foo() { std::cout << "Came to foo in file1.cpp" << std::endl; }

и

file2.cpp:

inline void foo() { std::cout << "Came to foo in file2.cpp" << std::endl; }

и вы связываете эти файлы вместе в исполняемом файле, вы нарушаете one-definition-rule, поскольку две версии функции inline не совпадают.

person R Sahu    schedule 26.03.2015
comment
Хорошее объяснение. - person Syfu_H; 10.04.2019