GCC 9.1 возвращает void & в качестве типа результата для явного вызова деструктора. Это ошибка? - программирование

GCC 9.1 возвращает void & в качестве типа результата для явного вызова деструктора. Это ошибка?

Я пытаюсь заставить эту проверку определенного класса работать, что основано на том факте, что decltype(std::declval<Foo>().~Foo()) является void если у Foo есть деструктор (который он имеет, если оно определено…), и в противном случае является плохо сформированным, вызывая SFINAE в этом случае.

Однако я не могу заставить код работать с GCC 9.1, и это потому, что GCC 9.1, кажется, считает этот тип void & если деструктор по умолчанию, рассмотрим этот пример:

#include <type_traits>

class Foo {
public:
// With this, the DestructorReturnType below becomes "void"
//    ~Foo () {} 
};

// … unless I specify the user-defined destructor above, in which case it is "void"
using DestructorReturnType = decltype(std::declval<Foo>().~Foo());

template<class T>
class TD;

// Says: aggregate 'TD<void&> t' has incomplete type and cannot be defined
TD<DestructorReturnType> t;

(доступно по адресу https://gcc.godbolt.org/z/K1TjOP)

Если я определяю пользователем пустой деструктор, тип переходит обратно в void. Также, если я вернусь к GCC 8.x.

Стандарт С++ 17 в [expr.call] гласит:

Если postfix-expression обозначает деструктор, тип выражения вызова функции void; [...]

Из-за всего этого я подозреваю, что GCC 8.x (и clang,...) верны, а GCC 9.1 просто неправильны. Или я что-то упустил?

4b9b3361

Ответ 1

Короче говоря: Да, это регрессия в GCC 9.1. void& даже не является допустимым типом, поэтому что-то очень неправильно. Очевидно, что проблему можно обойти, установив -fno-lifetime-dse компилятора -fno-lifetime-dse за счет (возможно, небольшого) -fno-lifetime-dse производительности.

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