2015-11-23 1 views
1

Я wan't отключить пользователь объявил деструкторы использования SFINAE в накидном подобном классе, как сделать это обычно для конструкторов в классах:Почему деструктор не может быть шаблоном?

#include <type_traits> 
#include <cstdlib> 

template< typename A, typename B > 
struct U 
{ 
    constexpr U() = default; 
    cosntexpr U(A _a) : a(_a), s{false} { ; } 
    constexpr U(B _b) : b(_b), s{true} { ; } 

    union 
    { 

     A a; 
     B b; 

    }; 

    bool s; 

    template< typename = std::enable_if_t< !(std::is_trivially_destructible<A>{} && std::is_trivially_destructible<B>{}) >, // disable if A and B is trivially destructible 
       bool is_noexcept = (noexcept(std::declval<A>().~A()) && noexcept(std::declval<B>().~B())) > // disable if A or B is not destructible 
    ~U() noexcept(is_noexcept) 
    { 
     if (s) { 
      b.~B(); 
     } else { 
      a.~A(); 
     } 
    } 
}; 

int main() 
{ 
    struct A {}; 
    struct B {}; 
    U< A, B > u; 
    static_assert(std::is_literal_type<A>{}); 
    static_assert(std::is_literal_type<B>{}); // => 
    static_assert(std::is_literal_type< U< A, B > >{}); 
    return EXIT_SUCCESS; 
} 

но получил ошибку:

main.cpp:24:5: error: destructor cannot be declared as a template 
    ~U() noexcept(is_noexcept) 
    ^
1 error generated. 
Failure! 

Есть ли теоретическая причина этого ограничения в C++? Или это просто «наследие»?

+0

@DavidHaim конструктор по умолчанию также не может получить параметры, но это может быть шаблон. – Orient

+0

Деструктор должен быть сгенерирован, конструктор по умолчанию - нет (класс может иметь другой конструктор). – Jarod42

+0

см. Мой ответ –

ответ

7

Любой класс, U, может иметь один и только один деструктор, который объявлен в этом классе с именем ~U() и не принимает точно никаких параметров.

Функция шаблона определяет семейство функций, где «семейство» описывает набор, содержащий один или несколько, без верхнего предела на число членов.

Эти две концепции являются взаимоисключающими. Класс не может одновременно иметь ровно один деструктор - семейство деструкторов.

+0

Использование SFINAE Я могу создать «семейство функций», чтобы обеспечить единственную жизнеспособную функцию в общем случае. – Orient

+0

Я не вижу противоречия: на первый взгляд нет непреодолимых препятствий, чтобы ввести возможность выбора деструкторов (или заставить компилятор предоставлять по умолчанию один условно). – Orient

+0

Это потому, что вы не понимаете разницы между определением шаблона и созданием шаблона. Шаблон - это спецификация, которая допускает множественные экземпляры, в зависимости от используемых параметров. Если разрешено только одно создание функции, эта функция не может быть шаблоном. SFINAE запускается только тогда, когда действительный шаблон впоследствии создается. Сообщение об ошибке, которое вы видите, происходит, когда проверка шаблона действительна. Если сам шаблон недействителен, код будет отклонен перед любой попыткой создать экземпляр шаблона. – Peter

1

Как работа вокруг, вы можете добавить слой и специализацию, что-то вроде:

template <typename A, typename B, 
      bool trivially_destructible = std::is_trivially_destructible<A>{} 
            && std::is_trivially_destructible<B>{}, 
      bool is_no_except = noexcept(std::declval<A>().~A()) 
         && noexcept(std::declval<B>().~B())> 
struct UdestructorImpl; 

template <typename A, typename B, bool is_no_except> 
struct UdestructorImpl<A, B, true, is_no_except> 
{ 
    ~UdestructorImpl() noexcept(is_no_except) = default; 
} 

template <typename A, typename B, bool is_no_except> 
struct UdestructorImpl<A, B, false, is_no_except> 
{ 
    ~UdestructorImpl() noexcept(is_no_except) = delete; 
} 

template< typename A, typename B > struct U : UdestructorImpl<A, B> 
{ 
    // Implementation 
}; 
+0

Использование EBO или этого метода является простым, но слишком подробным. – Orient

+0

Базы - единственный выбор для шаблонов вариационного класса. – Orient