Анонимные пространства имен и одно правило определения
Я нарушаю одно правило определения со следующей программой?
// 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
Это нарушает ODR. См. 3.2/5, где речь идет о внешних встроенных функциях (bar
):
в каждом определении D, соответствующие имена, смотрели вверх в соответствии с 3.4, относится к объекту, определенному в определении D, или относится к тому же объекту...
В этом случае bar
относится к двум различным версиям foo
, тем самым нарушая правило.
Ответ 2
Да, это определение bar()
нарушает правило одного определения. Вы создаете несколько определений, каждый из которых вызывает другую функцию под названием foo()
.
Как вы говорите, это было бы нарушением, даже если все версии foo()
идентичны, поскольку они все еще разные функции.