Может ли встроенная функция в заголовочном файле использовать константу, которая имеет внутреннюю связь?
Рассмотрим следующий код:
const int a = 0;
const std::string b = "hi";
inline void f_a1()
{
std::cout << a;
}
inline void f_b1()
{
std::cout << b;
}
inline void f_a2()
{
std::cout << &a;
}
inline void f_b2()
{
std::cout << &b;
}
Предположим, этот код существует в заголовочном файле, который будет включен в несколько блоков перевода.
Мое понимание встроенных функций заключается в том, что они должны быть одинаковыми в каждой единице перевода.
Мое понимание констант, использованных выше, заключается в том, что они косвенно static
т.е. внутренняя связь. Это означает, что каждая единица перевода получает свою собственную копию.
Так как встроенные функции, указанные выше, полагаются на эти константы, какие из этих функций, если таковые имеются, являются правильными?
1 ответ
Если функция включена в несколько единиц перевода, единственная действующая функция f_a1
,
Соответствующим условием является [basic.def.odr]/ 6, в котором говорится, что inline
Функция может появляться в нескольких единицах перевода, но только с учетом того, что:
[...] имя может относиться к энергонезависимой
const
объект с внутренней связью или без связи, если объект имеет одинаковый литеральный тип во всех определениях D, и объект инициализируется с помощью константного выражения (5.19), и объект не используется odr, и объект имеет то же значение в все определения D;
Как объекты const
они имеют внутреннюю связь в [basic.link]/ 3:
Имя, имеющее область имен (3.3.6), имеет внутреннюю связь, если это имя [...]
- энергонезависимая переменная, которая явно объявлена как const или constexpr и ни явно не объявлена как extern, ни ранее объявлена как имеющая внешнюю связь [...]
Однако получение адреса или формирование ссылки на переменную (например, для передачи аргумента) - это использование odr, поэтому f_a2
а также f_b2
являются недействительными f_b1
также недействителен, так как ostream
оператор вывода для std::string
принимает аргумент по ссылке; и даже если он принимает свой аргумент по значению, неявно вызываемый конструктор копирования будет принимать его аргумент по ссылке. f_a1
все в порядке, потому что int
оператор stream-out принимает аргумент по значению и копирует значение int const
это не odr-использование.