Що означає «використовувати ОРС»?


93

Це просто виникло в контексті іншого питання .

Очевидно, функції-члени в шаблонах класів створюються лише тоді, коли вони використовуються ODR. Хтось може пояснити, що саме це означає. У статті Вікіпедії про Правило одного визначення (ODR) не згадується " використання ODR ".

Однак стандарт визначає це як

Змінна, назва якої відображається як потенційно обчислюваний вираз, використовується з підтримкою, якщо це не об’єкт, який задовольняє вимогам щодо появи у константному виразі (5.19) і перетворення lvalue-to-rvalue (4.1) негайно застосовується.

у [basic.def.odr].

Редагувати: очевидно, це неправильна частина, і весь абзац містить кілька визначень різних речей. Це може бути відповідним для функції-члена шаблону класу:

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

Однак я не розумію, як це правило працює в декількох одиницях компіляції? Чи всі функції-члени мають інстанцію, якщо явно створюю екземпляр шаблону класу?


2
Зверніть увагу, що [basic.def.odr] / 6 застосовується до функцій-членів шаблонів класів "Може бути більше одного визначення [...]"
dyp

3
"Чи всі функції-члени мають інстанцію, якщо явно створюю екземпляр шаблону класу?" Так, див. [Temp.explicit] / 8 + 9
dyp

Відповіді:


72

Це просто довільне визначення, яке використовується стандартом, щоб вказати, коли потрібно надати визначення для сутності (на відміну від просто декларації). Стандарт не говорить просто "використовується", оскільки це може трактуватися по-різному залежно від контексту. І деяке використання ODR насправді не відповідає тому, що зазвичай асоціюється з "використанням"; наприклад, віртуальна функція завжди використовується ODR, якщо вона не є чистою, навіть якщо вона насправді ніде не викликається в програмі.

Повне визначення наведено у пункті 3.2 , другий абзац, хоча він містить посилання на інші розділи для завершення визначення.

Що стосується шаблонів, використання ОРС - це лише частина питання; інша частина - інстанціювання. Зокрема, § 14.7 охоплює випадки створення шаблону. Але вони пов’язані між собою: хоча текст у п. 14.7.1 (неявна інстанціація) є досить довгим, основним принципом є те, що шаблон буде створений лише тоді, коли він буде використаний, і в цьому контексті вживаний означає ODR. Таким чином, функція-член шаблону класу буде інстанційована, лише якщо вона викликана, або якщо вона є віртуальною, а сам клас інстанціюється. Сам стандарт розраховує на це в багатьох місцях: std::list<>::sortвикористання <окремих елементів, але ви можете створити екземпляр списку над типом елемента, який не підтримує <, якщо ви не викликаєте sortйого.


чи може використання ОДР збігатися з "матеріалізованими тимчасовими"?
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 ++?
Ранкаба

Але значення rvalue також може бути передане const int&? Чи міг статичний член const оцінюватися як rvalue?
scottxiao

8
+1 для стислого вступного речення: "Простим словом odr-used означає, що (змінна або функція) використовується в контексті, де має бути присутнім визначення цього слова"
Пол Масрі-Стоун,

1
Я не розумію, як ви компілюєте цей код. Вони в одному ТУ? Якщо вони є, F :: g_x вже був визначений раніше push_back, звичайно, він пройде. Чи не так?
Льюїс Чан,

1
@bigxiao " rvalue також може бути передано " Так, і тимчасовий об'єкт створюється компілятором та посиланням на цей об'єкт. OTOH при передачі значення lvalue, що означає передачу об'єкта, на який посилається оцінка lvalue: коли ви передаєте значення lvalue, можна очікувати, що параметр у функції посилається на правильний об'єкт. Компілятор не створює тимчасового. Якщо ви хочете тимчасового, зробіть один із operator+.
curiousguy
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.