Что значит "использовать ODR"?
Это возникло в контексте другого вопроса.
Очевидно, функции-члены в шаблонах классов создаются только в том случае, если они используются ODR. Может кто-нибудь объяснить, что именно это значит. В статье в Википедии об одном правиле определения (ODR) не упоминается "использование ODR".
Однако стандарт определяет это как
Переменная, имя которой появляется в качестве потенциально оцениваемого выражения, используется odr, если только она не является объектом, удовлетворяющим требованиям для появления в константном выражении (5.19), и преобразование lvalue-в-значение (4.1) применяется немедленно.
в [basic.def.odr].
Изменить: Очевидно, это неправильная часть, и весь абзац содержит несколько определений для разных вещей. Это может быть релевантным для функции-члена шаблона класса:
Неперегруженная функция, имя которой появляется в качестве потенциально оцененного выражения или члена набора функций-кандидатов, если она выбрана разрешением перегрузки при обращении к потенциально оцененному выражению, используется odr, если только она не является чисто виртуальной Функция и ее имя не определены явно.
Я, однако, не понимаю, как это правило работает для нескольких модулей компиляции? Все функции-члены создаются, если я явно создаю шаблон класса?
2 ответа
Это просто произвольное определение, используемое стандартом для указания, когда вы должны предоставить определение для сущности (в отличие от простого объявления). Стандарт не говорит просто "используется", потому что это может интерпретироваться по-разному в зависимости от контекста. И некоторое использование ODR на самом деле не соответствует тому, что обычно ассоциируется с "использованием"; например, виртуальная функция всегда используется ODR, если она не является чистой, даже если она фактически не вызывается нигде в программе.
Полное определение приведено в §3.2, второй абзац, хотя оно содержит ссылки на другие разделы для завершения определения.
Что касается шаблонов, использование ODR является лишь частью вопроса; другая часть - создание экземпляров. В частности, §14.7 охватывает, когда создается экземпляр шаблона. Но эти два взаимосвязаны: хотя текст в §14.7.1 (неявное создание экземпляров) довольно длинный, основной принцип заключается в том, что шаблон будет создаваться только в том случае, если он используется, и в этом контексте "используется" означает использование ODR. Таким образом, функция-член шаблона класса будет создаваться только в том случае, если она вызывается, или если она виртуальная и создается экземпляр самого класса. Сам стандарт рассчитывает на это во многих местах: std::list<>::sort
использования <
на отдельные элементы, но вы можете создать экземпляр списка по типу элемента, который не поддерживает <
до тех пор, пока ты не позвонишь sort
в теме.
Проще говоря, 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, сообщение об ошибке: неопределенная ссылка на `K::g_x'