Вызов деструктора с decltype и\или std::remove_reference

Можно ли вызвать деструктор (без удаления оператора), используя decltype и\или std::remove_reference? Вот пример:

#include <iostream>
#include <type_traits>

using namespace std;

class Test
{
    public:
    Test() {}
    virtual ~Test() {}
};

int main()
{
    Test *ptr;

    ptr->~Test(); // works
    ptr->~decltype(*ptr)(); // doesn't work
    ptr->~std::remove_reference<decltype(*ptr)>::type(); // doesn't work

return 0;
}

person user1266334    schedule 26.06.2013    source источник
comment
Нет, это невозможно.   -  person Andy Prowl    schedule 26.06.2013
comment
Деструктор не является типом.   -  person Pete Becker    schedule 26.06.2013
comment
... но вы можете использовать шаблон функции для явного вызова dtor (вывод типа). Хотя не уверен, что ты выиграешь.   -  person dyp    schedule 26.06.2013
comment
DyP, шаблон - возможное решение. Спасибо!   -  person user1266334    schedule 26.06.2013


Ответы (3)


Вы можете использовать шаблон псевдонима, чтобы получить неполное имя типа, когда все, что у вас есть, это полное имя типа. Следующее должно работать

template<typename T> using alias = T;
ptr->~alias<std::remove_reference<decltype(*ptr)>::type>();

Обратите внимание, что если бы remove_reference сработало, это все равно было бы опасно, потому что с помощью полного имени типа вы запретили бы вызов виртуального деструктора. При использовании шаблона псевдонима виртуальные деструкторы по-прежнему работают.

Обратите внимание, что GCC4.8, похоже, принимает

ptr->std::remove_reference<decltype(*ptr)>::type::~type();

Клэнг отвергает это. Я давно отказался от попыток понять, как работает поиск имени деструктора (если вы заглянете в исходники clang, то заметите, что разработчики clang тоже не следуют спецификации, потому что говорят, что здесь это не имеет смысла). Существуют DR, которые охватывают синтаксис вызова деструктора и то, как они искажаются. Поэтому я бы рекомендовал не использовать здесь сложный синтаксис.

person Johannes Schaub - litb    schedule 26.06.2013
comment
Вы уверены, что спецификаторы decltype не разрешены? например [expr.prim.general]/8 Имя класса или спецификатор decltype с префиксом ~ обозначает деструктор. - person dyp; 26.06.2013
comment
@DyP Думаю, я не говорил, что спецификаторы decltype не разрешены. Но это не имеет значения, так как спецификатор decltype будет обозначать ссылочный тип и поэтому не может использоваться в его примере. - person Johannes Schaub - litb; 26.06.2013
comment
Не могли бы вы объяснить это подробнее, пожалуйста? Я не понял случая, когда виртуальный деструктор не будет вызываться. - person user1266334; 26.06.2013
comment
@ user1266334 Я рекомендую открыть для этого другой вопрос. - person Johannes Schaub - litb; 26.06.2013

В случае, если ваш компилятор не поддерживает шаблон с помощью команды, вы можете сделать следующее:

Определите структуру шаблона:

template<class T> struct unwind_alias { static VOID destroy(T* ptr) { ptr->~T(); }; };

Используйте его, чтобы уничтожить объект

unwind_alias<std::remove_reference<decltype(*ptr)>::type>::destroy(ptr);

Надеюсь, это поможет любому.

person Oleg Karasik    schedule 21.09.2013

В C++17 вы также можете просто использовать std::destroy_at.

person deltacrux    schedule 29.10.2018