Search code examples
c++c++20c++-conceptsrequires-clause

Optional non-trivial destructor using requires


What is the correct way to declare an optional non-trivial destructor using C++ 20 requires? For copy constructor and move constructors it has worked for me to declare the non trivial requires copy/move constructor first and then the default declaration, but for destructors I'm getting weird behaviour:

#include <string>
#include <type_traits>

template<typename T>
concept TriviallyDestructible = std::is_trivially_destructible_v<T>;
template<typename T>
concept NotTriviallyDestructible = !TriviallyDestructible<T>;

template<typename T>
struct OptionalDestructor
{
    T value;

    ~OptionalDestructor() requires NotTriviallyDestructible<T>
    {

    }
    ~OptionalDestructor() = default;
};


int main()
{
    static_assert(TriviallyDestructible<OptionalDestructor<int>>);
    static_assert(!TriviallyDestructible<OptionalDestructor<std::string>>);
}

is not compiling on clang trunk for me, while

#include <string>
#include <type_traits>

template<typename T>
concept TriviallyDestructible = std::is_trivially_destructible_v<T>;
template<typename T>
concept NotTriviallyDestructible = !TriviallyDestructible<T>;

template<typename T>
struct OptionalDestructor
{
    T value;

    ~OptionalDestructor() = default;
    ~OptionalDestructor() requires NotTriviallyDestructible<T>
    {

    }
};


int main()
{
    static_assert(TriviallyDestructible<OptionalDestructor<int>>);
    static_assert(!TriviallyDestructible<OptionalDestructor<std::string>>);
}

is compiling the way I would expect it to. On apple clang I cannot get an optional destructor to compile at all, and MSVC has different behaviour consider orders again... Which compiler is behaving correctly here?

https://godbolt.org/z/Tvjo9e4nx

GCC seems to compile both orders.


Solution

  • GCC is correct. The order should not matter.

    Clang documentation indicates that it hasn't yet implemented P0848, which would make your example compile. It's surprising to me that Clang does compile the example in one order but not the other, and that MSVC behaves similarly, but I guess they just look at the first prospective destructor.