decltype для материализованного prvalues ​​доступа к элементам ведет себя неправильно - PullRequest
0 голосов
/ 16 мая 2018
#include <iostream>
#include <type_traits>

struct A { double x; };
int main() 
{

    const A && a1 = A();

    std::cout << std::is_same_v<decltype((a1.x)), const double&>;
    std::cout << std::is_same_v<decltype((std::move(a1).x)), const double&&>;
    std::cout << std::is_same_v<decltype((A().x)), double>;

}

Output:

111

Не должен decltype в последнем примере возвращать double && , поскольку согласно значения категории . A (). X является xзначением

xvalue

a.m, член выражения объекта, где a является r-значением, а m является нестатический элемент данных не ссылочного типа;

...

Протестировано с gcc7.1; gcc5.2; clang3.8; gcc4.9; gcc4.8; gcc4.7; в фрагменте кода en.cppreference.com/w/cpp/language/decltype

1 Ответ

0 голосов
/ 16 мая 2018

Строго по стандарту, похоже, вы правы, и должно быть double &&.Моя цепочка рассуждений (все цитаты из C ++ 17 (n4659)):

8.2.5 Доступ к членам класса [expr.ref]

1 Постфиксное выражение, за которым следуетточка . или стрелка ->, за которыми необязательно следует ключевое слово template (17.2), а за которым следует id-выражение , является постфиксным выражением....

2 Для первого параметра (точка) первое выражение должно быть glvalue, имеющим полный тип класса.

3 Сокращение postfix-expression.id-expression поскольку E1.E2, E1 называется выражением объекта .... Тип и категория значения E1.E2 определяются следующим образом.В оставшейся части 8.2.5 cq представляет либо const, либо отсутствие const, а vq представляет либо volatile, либо отсутствие volatile. cv представляет произвольный набор cv-квалификаторов, как определено в 6.9.3.

...

(4.2) Если E2 не является статичнымэлемент данных и тип E1 равен « cq1 vq1 X», а тип E2 равен « cq2 vq2 T», выражение обозначаетименованный член объекта, обозначенного первым выражением.Если E1 является lvalue, то E1.E2 является lvalue;в противном случае E1.E2 является значением xvalue....

Таким образом, если левый операнд . является значением x, то и результат всего выражения ..

8.2.3 Явныйпреобразование типов (функциональная запись) [expr.type.conv]

1 A спецификатор простого типа (10.1.7.2) или спецификатор типа (17.6), за которым следует необязательный список выражений в скобках или braced-init-list (инициализатор), создающий значение указанного типа с учетом инициализатора....

2 ... выражение является prvalue указанного типа, чей объект-результат инициализируется напрямую (11.6) с помощью инициализатора.

То есть A() isprvalue.

Наконец:

8 выражений [expr]

10 Всякий раз, когда выражение prvalue появляется как операнд оператора, который ожидает glvalue для этого операндапреобразование временной материализации (7.4) применяется для преобразования выражения в значение x.

В совокупности это означает, что A() является prvalue (из 8.2.3 / 2).Поскольку . требует, чтобы его операнд LHS был glvalue, применяется временное преобразование материализации (на 8/10), а результатом является xvalue.Итак, начиная с 8.2.5 / (4.2), поскольку E1 является значением x, равно E1.E2, что в вашем случае составляет A().x.

Что касается decltype:

10.1.7.2 Спецификаторы простых типов [dcl.type.simple]

4 Для выражения e тип, обозначаемый decltype(e), определяется следующим образом:

...

(4.3) ... если e является значением x, decltype(e) является T&&, где T является типом e;

Поскольку в вашем случае (A().x) было определено как xvalue, его dectlype должно быть double &&.

...