Что значит «использовать ODR»?

92

Это просто возникло в контексте другого вопроса .

Очевидно, функции-члены в шаблонах классов создаются только в том случае, если они используются ODR. Может кто-нибудь объяснить, что именно это означает. В статье в Википедии о Правиле одного определения (ODR) не упоминается « использование ODR ».

Однако стандарт определяет это как

Переменная, имя которой отображается как потенциально оцениваемое выражение, используется odr, если только это не объект, который удовлетворяет требованиям для появления в постоянном выражении (5.19), и немедленно применяется преобразование lvalue-to-rvalue (4.1).

в [basic.def.odr].

Изменить: по-видимому, это неправильная часть, и весь абзац содержит несколько определений для разных вещей. Это может быть актуально для функции-члена шаблона класса:

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

Однако я не понимаю, как это правило работает с несколькими единицами компиляции? Все ли функции-члены создаются, если я явно создаю экземпляр шаблона класса?

Сариен
источник
2
Обратите внимание, что [basic.def.odr] / 6 применяется к функциям-членам шаблонов классов «Может быть более одного определения [...]»
dyp
3
«Все ли функции-члены создаются, если я явно создаю экземпляр шаблона класса?» Да, см. [Temp.explicit] / 8 + 9
dyp

Ответы:

71

Это просто произвольное определение, используемое стандартом, чтобы указать, когда вы должны предоставить определение для объекта (в отличие от простого объявления). Стандарт не говорит просто «используется», потому что это может интерпретироваться по-разному в зависимости от контекста. И некоторое использование ODR на самом деле не соответствует тому, что обычно ассоциируется с «использованием»; например, виртуальная функция всегда используется ODR, если она не является чистой, даже если она фактически не вызывается нигде в программе.

Полное определение находится в §3.2 , втором абзаце, хотя он содержит ссылки на другие разделы для завершения определения.

Что касается шаблонов, использование ODR - это только часть вопроса; другая часть - создание экземпляра. В частности, §14.7 охватывает создание экземпляра шаблона. Но они связаны между собой: хотя текст в §14.7.1 (неявное создание экземпляра) довольно длинный, основной принцип заключается в том, что шаблон будет создан только в том случае, если он используется, и в этом контексте используется означает использование ODR. Таким образом, функция-член шаблона класса будет создаваться только в том случае, если она вызывается или если она виртуальная и создается экземпляр самого класса. Сам стандарт рассчитывает на это во многих местах: при std::list<>::sortиспользовании <отдельных элементов, но вы можете создать экземпляр списка по типу элемента, который не поддерживает <, если вы не вызываете sortего.

Джеймс Канце
источник
может ли использование ODR совпадать с «материализованными временными конструкциями»?
v.oddou
23

Проще говоря, odr-used означает, что что-то (переменная или функция) используется в контексте, где должно присутствовать определение этого.

например,

struct F {
   static const int g_x = 2;
};

int g_x_plus_1 = F::g_x + 1; // in this context, only the value of g_x is needed.
                             // so it's OK without the definition of g_x

vector<int>  vi;
vi.push_back( F::g_x );      // Error, this is odr-used, push_back(const int & t) expect
                             // a const lvalue, so it's definition must be present

Обратите внимание, что приведенный выше push_back передан в MSVC 2013, это поведение не соответствует стандарту, оба gcc 4.8.2 и clang 3.8.0 не прошли, сообщение об ошибке: undefined ссылка на `K :: g_x '

Чжаоруфэй
источник
Можно ли использовать odr-элемент статических данных, как vi.push_back( F::g_x );в c ++?
Ранкаба
Но можно const int&ли передать значение rvalue? Можно ли преобразовать статический элемент const в rvalue?
scottxiao
8
+1 за краткое вводное предложение: «Простым словом odr-used означает, что что-то (переменная или функция) используется в контексте, где должно присутствовать определение этого».
Пол Масри-Стоун
1
Я не понимаю, как вы компилируете этот код. Они в одном ТУ ?. Если да, то F :: g_x уже был определен раньше push_back, конечно, пройдет. Не так ли?
Льюис Чан
1
@bigxiao " rvalue также может быть передано " Да, и временный объект создается компилятором и ссылкой, привязанной к этому объекту. OTOH при передаче lvalue, что означает передачу объекта, на который ссылается оценка lvalue: когда вы передаете lvalue, вы можете ожидать, что параметр в функции будет ссылаться на правильный объект. Компилятор не создает временный. Если вы хотите временный, сделайте его с помощью operator+.
curiousguy 05