Подтвердить что ты не робот

Почему адрес нестатического члена не разрешен как шаблонный непиковый параметр?

template <int * ip> struct test {};

struct q {
    static int a;
    int b;

    constexpr q(int b_) : b(b_) {}
};

int i;
constexpr q q0(2);

int main()
{
    constexpr test<&i> t1;      // Works fine
    constexpr test<&q::a> t2;   // Works 
    constexpr test<&q0.b> t3;   // Does not work; address of non-static member?

    return 0;
}

Объявление t3 в вышеуказанной части кода не выполняется, несмотря на то, что аргумент шаблона &q0.b известен во время компиляции. Некоторые поисковые роботы показали, что это запрещено стандартом (раздел 14.3.2):

[Примечание. Адреса элементов массива и имен или адресов нестатических членов класса не являются допустимыми шаблонами-аргументами.

X & s.m > x4;//ошибка: адрес нестатического membe

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

4b9b3361

Ответ 1

Во-первых, чтобы использовать указатели/ссылки на подобъекты, вам нужно будет их калечить. Это довольно большое начинание.

Во-вторых, и, что еще важнее, из N4198:

Ограничение, которое выражение константы должно называть полным объект сохраняется, чтобы избежать проблем с псевдонимом с указателями на подобъектов:

struct A { int x, y; } a;
template<int*> struct Z;
using B = Z<&a.x + 1>;
using C = Z<&a.y>;
// Are B and C the same type?

Чтобы процитировать Richard Smith,

Ответ "да" проблематичен, потому что есть вещи, которые вы можете сделать с указателем на [ a.y], который имел бы поведение undefined, если выполняется по указателю за конец [a.x]. Ответ "нет" проблематичны, поскольку они (в типичных реализациях) представляют собой тот же адрес.

Ответ 2

Замените свою основную часть этим фрагментом кода

int main(void)
{    
constexpr static int bb = 5;    
constexpr test<&bb> t;    
return 0;
}

и вы получите ошибку bb не может использоваться в качестве аргумента шаблона, потому что у него нет привязки (чтобы не ошибиться с персоналом, связанным с компоновщиком).

Элементы данных класса не могут быть доступны, если они не привязаны к объекту и не могут быть приняты во внимание при создании экземпляра шаблона, поскольку данные не имеют привязки, т.е. они не определены символами и поэтому не могут использоваться в качестве аргументов шаблона.

Сказав это, сделав readelf, вы можете проверить это:

48: 00000000004006ac     4 OBJECT  LOCAL  DEFAULT   14 q0


68: 000000000060097c     0 NOTYPE  GLOBAL DEFAULT  ABS __bss_start
69: 0000000000600978     4 OBJECT  GLOBAL DEFAULT   23 q::a

но не определено q0.b. Альтернативой было бы назвать (mangle) не статические члены класса, которые лишали бы динамические возможности языка.