Ссылки Rvalue в условном выражении

typedef decltype(true ? (long&&)0 : (long&&)0) T;

Каким должно быть Т?

Согласно gcc (4.7), это long. Судя по лязгу (багажник), это long&&. Это различие приводит к тому, что clang не может скомпилировать код, использующий libstdc++ gcc 4.7. Кто прав?

ОБНОВЛЕНИЕ: как указывает ildjarn, Clang прав, и, как указывает Richard Smith, ошибка libstdc++ связана с ошибкой в ​​стандарте . Вот соответствующая ошибка GCC и соответствующий отчет о дефектах.


person HighCommander4    schedule 28.04.2012    source источник
comment
Является ли это упрощенной формой некоторого кода шаблона, который включает &&?   -  person Nicol Bolas    schedule 28.04.2012
comment
@NicolBolas: Да. Это актуально?   -  person HighCommander4    schedule 28.04.2012
comment
Главное, что мне было интересно, происходит ли это только с базовыми типами или также происходит с пользовательскими?   -  person Nicol Bolas    schedule 28.04.2012
comment
@NicolBolas: это происходит и с пользовательскими типами.   -  person HighCommander4    schedule 28.04.2012
comment
libstdc++ содержит эту ошибку из-за неправильной спецификации для std::common_type в стандарте C++. На странице статуса C++ Clang есть патч для libstdc++4.7, исправляющий эту ошибку: clang.llvm.org/ cxx_status.html   -  person Richard Smith    schedule 30.04.2012


Ответы (1)


Кланг прав. N3337 §7.1.6.2/4:

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

  • если e – это выражение-идентификатор без скобок или доступ к члену класса без скобок, decltype(e) – это тип сущности, названной e. Если такой сущности нет или если e называет набор перегруженных функций, программа плохо сформирована;
  • в противном случае, если e — это значение x, decltype(e) – это T&&, где T – это тип e;
  • в противном случае, если e — это lvalue, decltype(e) — это T&, где T — это тип e;
  • в противном случае decltype(e) является типом e.

Операнд спецификатора decltype является невычисленным операндом.

§5/6:

[ Примечание. Выражение является значением x, если оно:

  • результат вызова функции, явного или неявного, тип возвращаемого значения которого является ссылкой rvalue на тип объекта,
  • приведение к rvalue-ссылке на тип объекта,
  • выражение доступа к члену класса, обозначающее нестатический член данных нессылочного типа, в котором выражение объекта является значением x, или
  • выражение указателя на элемент .*, в котором первый операнд является значением x, а второй операнд является указателем на элемент данных.

В общем, результатом этого правила является то, что именованные ссылки rvalue обрабатываются как lvalue, а неименованные ссылки rvalue на объекты обрабатываются как xvalue; Ссылки rvalue на функции обрабатываются как lvalue независимо от того, именованы они или нет. —конец примечания ]

Раньше я опасался, что литерал 0 может каким-то образом помешать квалифицировать это как тип объекта в этом контексте, но §3.9/8 проясняет ситуацию:

Тип объекта — это тип (возможно, cv-квалифицированный), который не является типом функции, не ссылочным типом и не пустым типом.

Условный оператор здесь ни на что не влияет §5.16/4:

Если второй и третий операнды являются gl-значениями одной и той же категории значений и имеют один и тот же тип, результат имеет этот тип и категорию значений и является битовым полем, если второй или третий операнд является битовым полем, или если оба являются битовыми полями.

В этом случае оба относятся к одной и той же категории значений (xvalue), а значения x являются значениями gl.

person ildjarn    schedule 28.04.2012
comment
Фактический пример был typedef decltype(true ? declval<long>() : declval<long>()) T;, где declval<T> возвращает T&&, я просто упростил его. Это что-то меняет? - person HighCommander4; 28.04.2012
comment
@HighCommander4: Нет, это полностью подкрепляет мой аргумент, поскольку он идеально соответствует первому пункту в §5/6. - person ildjarn; 28.04.2012