Реализация is_destructible с обнаруженной идиомой - PullRequest
0 голосов
/ 24 ноября 2018

Вот моя реализация 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 скомпилирована успешно и прошла весь набор тестов libstdcxx , в то время как gcc не удалось скомпилировать:

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&&]':

Итак, gcc не может выполнить SFINAE для using has_dtor = decltype(std::declval<U&>().~U());.

Вопрос:

  1. Какой объект компилятора здесь стандарт?
  2. Какое самое элегантное решение / обходной путь здесь?Пути, которые я могу придумать, немного уродливы

1 Ответ

0 голосов
/ 24 ноября 2018

GCC, похоже, не работает при обработке ~T(), где T является ссылкой скалярного типа.

Он принимает следующий код , который явно глючит на [expr.pseudo] / 2 :

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

Я бы использовал if constexpr для реализации:

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;
    }
}

Это работает и с GCC.

...