6 Basic concepts [basic]

6.2 One-definition rule [basic.def.odr]

Ни одна единица перевода не должна содержать более одного определения любой переменной, функции, типа класса, типа перечисления или шаблона.

Выражение is,potentially evaluated если оно не является его unevaluated operand частным выражением. Наборpotential results выраженияe определяется следующим образом:

  • Еслиe есть id-expression, набор содержит толькоe.

  • Еслиe -subscripting operation с операндом-массивом, набор содержит потенциальные результаты этого операнда.

  • Еслиe -class member access выражение, набор содержит потенциальные результаты объектного выражения.

  • Еслиe -pointer-to-member выражение, второй операнд которого является постоянным выражением, набор содержит потенциальные результаты объектного выражения.

  • Еслиe имеет форму(e1), набор содержит потенциальные результатыe1.

  • Еслиe -conditional выражение glvalue , набор представляет собой объединение наборов потенциальных результатов второго и третьего операндов.

  • Еслиe - acomma expression, набор содержит потенциальные результаты правого операнда.

  • В противном случае набор пуст.

[ Note: Этот набор является (возможно, пустым) набором id-expressions, каждое из которых является либоe частью выраженияe. [ Example: В следующем примере набор потенциальных результатов инициализатораn содержит первоеS​::​x подвыражение, но не второе S​::​x подвыражение.

struct S { static const int x = 0; };
const int &f(const int &r);
int n = b ? (1, S::x)  // S​::​x is not odr-used here
          : f(S::x);   // S​::​x is odr-used here, so a definition is required

end example] ]end note

Переменнаяx , имя которой отображается как потенциально оцениваемое выражение,ex - этоodr-used ,ex если только применениеlvalue-to-rvalue conversion к неx даетconstant expression , который не вызывает никаких нетривиальных функций, и, еслиx является объектом,ex является элементом набора потенциальных результатов выраженияe, где либоlvalue-to-rvalue conversion применяется кe, илиe этоdiscarded-value expression. this используется odr, если оно появляется как потенциально оцениваемое выражение (в том числе как результат неявного преобразования в теле anon-static member function). Виртуальная функция-член используется odr, если она не чистая. Функция , чье имя появляется как потенциально-оценивали выражение ODR-используется , если он является единственным результатом поиска или выбранный элемент из набора перегруженных функций ([basic.lookup],[over.match],[over.over]), если это не является чистой виртуальной функции и либо его имя не явно квалифицировано, или выражение образует указатель на member ([expr.unary.op]). [ Note: Это касаетсяcalls to named functions,operator overloading, user-defined conversions, функции распределения для размещения new-expressions, а также инициализация не по умолчанию ([dcl.init]). Конструктор, выбранный для копирования или перемещения объекта типа класса, используется odr, даже если вызов фактически отменен реализацией ([class.copy]). ] Функция выделения или освобождения для класса используется odr, появляясь в потенциально оцениваемом выражении, как указано в и . Функция освобождения класса используется odr выражением удаления, появляющимся в потенциально оцениваемом выражении, как указано в и . Функция выделения или освобождения без размещения для класса используется odr определением конструктора этого класса. Функция освобождения без размещения для класса используется odr определением деструктора этого класса или выбирается поиском в точке определения виртуального деструктора ( ). Функция оператора присваивания в классе используется odr неявно определенной функцией присваивания копии или присваивания перемещения для другого класса, как указано в . Конструктор для класса используется odr, как указано в . Деструктор для класса используется odr, если это так .end notenew-expression[expr.new] [class.free][expr.delete][class.free][class.dtor]27[class.copy][dcl.init]potentially invoked

Каждая программа должна содержать ровно одно определение каждой не встроенной функции или переменной, которая используется odr в этой программе вне adiscarded statement; диагностика не требуется. Определение может появиться в программе явно, его можно найти в стандартной или пользовательской библиотеке или (при необходимости) оно определено неявно (см.[class.ctor],[class.dtor] И [class.copy]). Встроенная функция или переменная должна быть определена в каждой единице трансляции, в которой она используется odr вне отвергнутого оператора.

В единице перевода требуется ровно одно определение класса, если класс используется таким образом, который требует, чтобы тип класса был полным. [ Example: Следующая полная единица перевода составлена ​​правильно, хотя в ней никогда не определяетсяX:

struct X;                       // declare X as a struct type
struct X* x1;                   // use X in pointer formation
X* x2;                          // use X in pointer formation

end example] [ Note: Правила для объявлений и выражений описывают, в каких контекстах требуются полные типы классов. Тип классаT должен быть полным, если:

end note]

Там может быть более одного определенияclass type, enumeration type, инлайн функции с внешним связыванием ([dcl.inline]), инлайн переменной с внешним связыванием ([dcl.inline]),class template, нестатическийfunction template, static data member of a class template,member function of a class templateили шаблон специализации , для которых некоторые параметры шаблона не указаны ([temp.spec],[temp.class.spec]) в программа при условии, что каждое определение появляется в разных единицах перевода, и при условии, что определения удовлетворяют следующим требованиям. Если такая сущностьD определена в нескольких единицах перевода, то

  • каждое определениеD должно состоять из одной и той же последовательности токенов; а также

  • в каждом определенииDсоответствующие имена,[basic.lookup]выполняемые в соответствии с поиском, должны относиться к объекту, определенному в определенииD, или должны относиться к тому же объекту после overload resolution и после сопоставления частичной специализации шаблона ([temp.over]), за исключением того, что имя может ссылаться на

    • энергонезависимыйconst объект с внутренней связью или без нее, если объект

      • имеет один и тот же буквальный тип во всех определенияхD,

      • инициализируется сconstant expression,

      • не используется odr ни в одном определенииD, и

      • имеет одинаковое значение во всех определенияхD,

      или

    • ссылка с внутренней связью или без нее, инициализированная константным выражением, так что ссылка ссылается на один и тот же объект во всех определенияхD;

    а также

  • в каждом определенииDсоответствующие объекты должны иметь одинаковую языковую связь; а также

  • в каждом определенииDупомянутых перегруженных операторов, неявных вызовов функций преобразования, конструкторов, функций оператора new и функций удаления оператора, должны ссылаться на одну и ту же функцию или на функцию, определенную в определенииD; а также

  • в каждом определенииDаргумент по умолчанию, используемый (неявным или явным) вызовом функции, обрабатывается так, как если бы его последовательность лексем присутствовала в определенииD; то есть аргумент по умолчанию подчиняется требованиям, описанным в этом параграфе (и, если аргумент по умолчанию имеет подвыражения с аргументами по умолчанию, это требование применяется рекурсивно).28

  • ifD является классом с неявно объявленным constructor, это как если бы конструктор был неявно определен в каждой единице перевода, где он используется odr, и неявное определение в каждой единице перевода должно вызывать один и тот же конструктор для подобъектаD. [Example:

    // translation unit 1:
    struct X {
      X(int, int);
      X(int, int, int);
    };
    X::X(int, int = 0) { }
    class D {
      X x = 0;
    };
    D d1;                           // X(int, int) called by D()
    
    // translation unit 2:
    struct X {
      X(int, int);
      X(int, int, int);
    };
    X::X(int, int = 0, int = 0) { }
    class D {
      X x = 0;
    };
    D d2;                           // X(int, int, int) called by D();
                                    // D()'s implicit definition violates the ODR
    

    end example]

ЕслиD является шаблоном и определен в нескольких единицах перевода, то предыдущие требования должны применяться как к именам из охватывающей области действия шаблона, используемой в определении шаблона ([temp.nondep]), так и к зависимым именам в точке создания экземпляра ([temp.dep]). Если определения D удовлетворяют всем этим требованиям, то поведение будет таким, как если бы было одно определениеD. Если определения D не удовлетворяют этим требованиям, поведение не определено.

Реализация не требуется для вызова функций выделения и освобождения из конструкторов или деструкторов; однако это допустимый метод реализации.

[dcl.fct.default] описывает, как ищутся имена аргументов по умолчанию.