#c #namespaces #one-definition-rule
#c #пространства имен #правило одного определения
Вопрос:
Нарушаю ли я правило единого определения в следующей программе?
// foo.hpp
#ifndef FOO_HPP_
#define FOO_HPP_
namespace {
inline int foo() {
return 1;
}
}
inline int bar() {
return foo();
}
#endif
//EOF
и
// m1.cpp
#include "foo.hpp"
int m1() {
return bar();
}
//EOF
и
// m2.cpp
#include "foo.hpp"
int m2() {
return bar();
}
//EOF
и, наконец,
// main.cpp
#include <iostream>
int m1();
int m2();
int main(int, const char* [])
{
int i = m1();
int j = m2();
std::cout << (i j) << std::endl;
return 0;
}
// EOF
В приведенном выше обратите внимание, что foo()
это определено в анонимном пространстве имен, поэтому я ожидаю, что каждая единица перевода m1.cpp
и m2.cpp
получит свою собственную версию, поэтому нарушения ODR нет. С другой стороны, bar()
это просто обычная старая встроенная функция, которая вызывает 2 разных foo
s. Так что это нарушает ODR, верно?
Обновление: ранее у меня были макросы в определении foo
, которые изменяли возвращаемое значение и каждое из m1
и m2
определяли макрос по-разному перед включением foo.hpp
. (И в этом предыдущем примере g
будет создан двоичный файл, который выводится (i j)
со значением, отличным от ожидаемого.) Но на самом деле эта программа нарушает ODR, даже если тело foo()
идентично.
Комментарии:
1. Я думаю, это ясно иллюстрирует, почему использование анонимных пространств имен или статических функций в файлах заголовков приносит проблемы 🙂
Ответ №1:
Это нарушает ODR. См. 3.2 / 5, в котором говорится о внешних встроенных функциях ( bar
):
в каждом определении D соответствующие имена, просмотренные в соответствии с 3.4, должны ссылаться на объект, определенный в определении D, или должны ссылаться на тот же объект…
В этом случае bar
ссылается на две разные версии foo
, тем самым нарушая правило.
Ответ №2:
Да, это определение bar()
действительно нарушает правило единого определения. Вы создаете несколько определений, каждое из которых вызывает другую вызываемую функцию foo()
.
Как вы говорите, это было бы нарушением, даже если бы все версии foo()
были идентичны, поскольку они все равно являются разными функциями.