Почему S:: x не используется odr?

Рассмотрим этот пример из cppreference:

struct S { static const int x = 1; };
void f() { &S::x; } // discarded-value expression does not odr-use S::x

Я согласен с тем, что &S::x является выражением отбрасываемого значения, так как в стандарте говорится (9.2, абзац 1 [stmt.expr] из n4700)

Операторы выражений имеют форму

expression-statement:
    expression_opt ;

Выражение представляет собой выражение с отброшенным значением (раздел 8)...

Однако, достаточно ли для S::x не использовать odr? 6.2, пункт 3 [basic.def.odr] состояния

Переменная x, имя которой отображается как потенциально оцененное выражение ex, является odr-используемым ex, если

  • ...
  • Если x является объектом, ex является элементом набора потенциальных результатов выражения e, где либо
    • преобразование lvalue-to-rvalue (7.1) применяется к e или
    • e - это выражение с отброшенным значением (раздел 8).

Проблема состоит в том, что выражение с отброшенным значением &S::x не имеет потенциальных результатов (это означает, что S::x не является потенциальным результатом &S::x), как вы можете видеть из пункта 6.2 главы 6.2 [basic.def.odr]:

... Множество потенциальных результатов выражения e определяется следующим образом:

  • Если e является id-выражением (8.1.4), набор содержит только e.
  • Если e - операция подписи (8.2.1) с операндом массива, набор содержит потенциальные результаты этого операнда.
  • ...
  • В противном случае набор пуст.

Затем, как вы можете объяснить, что S::x не используется odr?

Ответы

Ответ 2

При объявлении const int он может быть полностью отброшен компилятором, если вы не используете его адрес. взятие адреса не достаточно.

Отброшено не означает, что значение не оценивается, но оно означает, что нет адреса памяти, содержащего значение const, компилятор просто заменяет константную переменную на ее значение, поскольку это был просто макрос.

Кроме того, при нахождении указателя на него и возврате значения из указателя не сильно впечатляет компилятор, он просто игнорирует его и использует значение.

Следующий код показывает это, этот код можно скомпилировать и запустить (я проверяю его несколькими компиляторами, я все еще не уверен, что он успешно скомпилирован всеми...), несмотря на то, что S::x не был объявлен:

#include <iostream>
using namespace std;
struct S
{
    static const int x=0; 
};
//const int S::x; //discarded
int main()
{
    const int *px = &S::x;  //taking the address
    cout<< *px <<endl; //print the value - OK
    return 0;
}

Но если я попытаюсь использовать сам адрес (а не значение), например:

cout<< px <<endl; //print the address - Will be failed

ссылка не удалась: "неопределенная ссылка на S::x ".

Поэтому мой вывод: принимать адрес, не используя его, не учитывается вообще.

Ответ 3

Нашел этот и этот ответ вроде как отвечает на ваш вопрос:

Может быть более одного определения типа класса, типа перечисления, встроенной функции с внешней связью, шаблона класса, шаблона нестатической функции, статического члена данных шаблона класса, функции-члена шаблона класса или специализированной специализации шаблона, для которой некоторые параметры шаблона не указаны в программе, при условии, что каждое определение отображается в другой единицы перевода и при условии, что определения удовлетворяют следующим требованиям. Учитывая такой объект с именем D, определенный более чем в одной единицы перевода, тогда

  • ....

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

  • ...

... Если определения D удовлетворяют всем этим требованиям, то программа должна вести себя так, как если бы было одно определение D....