встроенная функция может быть определена несколько раз в программе, как
Пока определения идентичны
Нет. («Идентичный» здесь даже не является четко определенной концепцией.)
Формально определения должны быть эквивалентны в каком-то очень сильном смысле, который даже не имеет смысла как требование и о котором никто не заботится:
// in some header (included in multiple TU):
const int limit_max = 200; // implicitly static
inline bool check_limit(int i) {
return i<=limit_max; // OK
}
inline int impose_limit(int i) {
return std::min(i, limit_max); // ODR violation
}
Такой код вполне обоснован, но формально нарушает одно правило определения:
в каждом определении D, соответствующие имена, смотрел в соответствии с
6.4 [basic.lookup] должен ссылаться на объект, определенный в определении D, или должен ссылаться на тот же объект после перегрузки
разрешение (16.3 [over.match]) и после сопоставления частичного шаблона
специализация (17.9.3 [temp.over]), за исключением того, что имя может относиться к
константный объект с внутренней связью или без нее, если объект имеет такую же
литеральный тип во всех определениях D, и объект инициализируется
с постоянным выражением (8.20 [expr.const]), и значением (но не
адрес) объекта используется , и объект имеет то же значение
во всех определениях D;
Поскольку исключение не позволяет использовать объект const с внутренней связью (const int
неявно статичен) с целью непосредственной привязки ссылки на const (а затем использовать ссылку только для ее значения). Правильная версия:
inline int impose_limit(int i) {
return std::min(i, +limit_max); // OK
}
Здесь значение limit_max
используется в унарном операторе + и , тогда константная ссылка привязывается к временному значению, инициализированному этим значением . Кто на самом деле это делает?
Но даже комитет не верит, что формальные ODR имеют значение, как мы видим в Core Issue 1511 :
1511. постоянные переменные и правило одного определения
Раздел: 6.2 [basic.def.odr] Статус: CD3 Отправитель: Ричард
Смит Дата: 2012-06-18
[Перемещено в ДР на собрании в апреле 2013 года.]
Эта формулировка, возможно, недостаточно ясна для примера, подобного:
const volatile int n = 0;
inline int get() { return n; }
Мы видим, что комитет считает, что это вопиющее нарушение намерения и цели ODR, как написано , код, который читает различные изменчивые объекты в каждом TU, то есть код, который имеет видимый побочный эффект на другой объект, так что другой видимый побочный эффект, в порядке, потому что мы не заботимся о том, что .
Важно то, что эффект встроенной функции является примерно эквивалентным: выполнение изменяемого чтения int, что является очень слабой эквивалентностью, но достаточной для естественного использования *1057* ODR, равного безразличие экземпляра: какой конкретный экземпляр встроенной функции не имеет значения и не может иметь значения .
В частности, значение, читаемое энергозависимым чтением, по определению не известно компилятору, поэтому условие post и инварианты этой функции, проанализированные компилятором, одинаковы.
При использовании разных определений функций в разных TU, вам нужно убедиться, что они строго эквивалентны с точки зрения вызывающего: что никогда нельзя удивить вызывающего, заменив одно на другое. Это означает, что наблюдаемое поведение должно быть точно таким же , даже если код отличается.
Если вы используете разные параметры компилятора, они не должны изменять диапазон возможных результатов функции (возможно, если смотреть компилятором).
Потому что «стандарт» (который на самом деле не является спецификацией языка программирования) позволяет объектам с плавающей запятой иметь реальное представление, не допускаемое их официально объявленным типом, совершенно без ограничений, используя любые энергонезависимые квалифицированные плавающие Тип точки в любом множественно определенном субъекте для ODR кажется проблематичным, если только вы не активируете режим «double
означает double
» (который является единственным нормальным режимом).