3

Here is my implementation of is_destructible_v:

template<class T>
struct is_unknown_bound_array : std::false_type
{};
template<class T>
struct is_unknown_bound_array<T[]> : std::true_type
{};

template<typename T, typename U = std::remove_all_extents_t<T>>
using has_dtor = decltype(std::declval<U&>().~U());

template<typename T>
constexpr bool is_destructible_v
    = (std::experimental::is_detected_v<has_dtor, T> or std::is_reference_v<T>)
        and not is_unknown_bound_array<T>::value
        and not std::is_function_v<T>;

template<typename T>
struct is_destructible : std::bool_constant<is_destructible_v<T>>
{};

clang compiled happily and passed all libstdcxx's testsuite, while gcc failed to compile:

prog.cc:177:47: error: 'std::declval<int&>()' is not of type 'int&'

 177 | using has_dtor = decltype(std::declval<U&>().~U());    
     |                           ~~~~~~~~~~~~~~~~~~~~^
prog.cc: In substitution of 'template<class T, class U> using has_dtor = decltype (declval<U&>().~ U()) [with T = int&&; U = int&&]':

So, gcc cannot do SFINAE on using has_dtor = decltype(std::declval<U&>().~U());.

Question:

  1. Which compiler object to standard here?
  2. What's the most elegant solution/workaround here? The ways I can think of is a little ugly
Chen Li
  • 4,824
  • 3
  • 28
  • 55
  • It seems that GCC tries to make sure that the the type of expression `a` in `a.~B()` is the same as `B` without instantiating the function template, https://wandbox.org/permlink/4rhdNq4w7MMSIkcR – Piotr Skotnicki Nov 24 '18 at 11:05
  • msvc also can compile(though it doesn't support `and`, `or`, `not`) https://godbolt.org/z/b9-Ii8 – Chen Li Nov 25 '18 at 10:58
  • icc can compile: https://godbolt.org/z/ktZB3w – Chen Li Nov 25 '18 at 10:59

1 Answers1

4

GCC seems to be broken when handling ~T() where T is a reference of scalar type.

It accepts the following code, which is clearly buggy per [expr.pseudo]/2:

template<typename T> using tester = decltype(int{}.~T(), char{});
tester<int&> ch;
int main() {}

I would use if constexpr to implement:

template<class T>
constexpr bool my_is_destructible() {
    if constexpr (std::is_reference_v<T>) {
        return true;
    } else if constexpr (std::is_same_v<std::remove_cv_t<T>, void>
            || std::is_function_v<T>
            || is_unknown_bound_array<T>::value ) {
        return false;
    } else if constexpr (std::is_object_v<T>) {
        return std::experimental::is_detected_v<has_dtor, T>;
    } else {
        return false;
    }
}

It works with GCC too.

llllllllll
  • 16,169
  • 4
  • 31
  • 54