对于明确的析构函数调用,GCC 9.1返回void&作为结果类型。这是错误吗?

Luk*_*rth 21 c++ gcc language-lawyer c++17

I'm trying to get this is-class-defined-check to work, which relies on the fact that decltype(std::declval<Foo>().~Foo()) is void if Foo has a destructor (which it has if it is defined…) and is ill-formed otherwise, invoking SFINAE in this case.

However, I can't get the code to work with GCC 9.1, and that is because GCC 9.1 seems to consider that type to be void & if the destructor is defaulted, consider this example:

#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;
Run Code Online (Sandbox Code Playgroud)

(available at https://gcc.godbolt.org/z/K1TjOP )

If I user-define an empty destructor, the type jumps back to void. Also if I switch back to GCC 8.x.

The C++17 standard states in [expr.call]:

If the postfix-expression designates a destructor, the type of the function call expression is void; […]

Because of all this, I suspect that GCC 8.x (and clang, …) are correct, and GCC 9.1 is just wrong. Or am I missing something?

Luk*_*rth 12

长话短说:是的,这是GCC 9.1中的回归void&甚至不是有效的类型,所以有些错误。显然,可以通过设置-fno-lifetime-dse编译器选项来解决此问题,而以(可能的)轻微的性能代价为代价。此外,9.1之前的GCC版本也不受影响。

如果您因为也在尝试实现上述is-class-defined-check而找到了答案,那么我认为使用sizeof的简单得多的表单应该定义明确,有效并且不会受到此bug的攻击。

  • 不要犹豫,接受自己的答案;显然,这是正确的。 (2认同)