调用模板 class 的析构函数,预期 class-name 在 ‘(’ 标记之前

Call the destructor of a template class, expected class-name before ‘(’ token

我有一个例外情况,我需要调用 class 的析构函数来清除联合内存。我们还不能使用 std::variant。联合中的 class 是基于模板的,其定义类似于:

template<class TYPE>
class BaseTemplate
{
  public:
    BaseTemplate() = default;
    ~BaseTemplate() = default;

    // Other useful functions.

  private:
    TYPE value;
}

现在我们定义不同的类型使用:

using X = BaseTemplate<int>;
// Other using definitions

在较早的情况下 X 是从 BaseTemplate.

派生的 classes
class X : public BaseTemplate<int>
{ 
  X() = default;
  ~X() override = default; // In this case ~BaseTemplate was virtual.

  // Nothing useful so we would like to remove this class.
};

在以前的情况下,我们可以这样调用析构函数:

X variableX;
variableX.~X();

在使用 using X = BaseTemplate<int>; 的新情况下,这会导致错误:expected class-name before ‘(’ token。那么在这种情况下我该如何调用析构函数呢?

复制代码:

#include <iostream>
namespace a 
{
class Base
{
  public:
    Base() = default;
    virtual ~Base() = default;

    virtual void foo() = 0;
};

template<class TYPE>
class BaseTemplate : public Base
{
  public:
    BaseTemplate() = default;
    ~BaseTemplate() override = default;

    // Other useful functions.
    void set(const TYPE& v) 
    {
      value = v;
    }

    TYPE get() const 
    {
      return value;
    }

    void foo() final
    {
        value *= 2;
    }

  private:
    TYPE value;
};

using X = BaseTemplate<int>;
using Y = BaseTemplate<unsigned int>;
using Z = BaseTemplate<float>;

} // End of namespace a

union XYZ
{
  XYZ() {}
  ~XYZ() {}
  a::X variableX;
  a::Y variableY;
  a::Z variableZ;
};

XYZ xyz;

int main()
{
    // Inplace new operator to initialize x
    new(&xyz.variableX) a::X;

    xyz.variableX.set(1);
    xyz.variableX.foo();
    std::cout << "Result: " << xyz.variableX.get() << std::endl;

    xyz.variableX.~X();
}

variableX 的析构函数称为 ~BaseTemplate()。但是,如果 X 在范围内并解析为 BaseTemplate<int>,它也将用作析构函数的别名。

如果 X 不在范围内:

some::random_namespace::X variableX;

// variableX.~X();  X not in scope, will not work

variableX.some::random_namespace::X::~X();  // Works, but confusing

// variableX.~decltype(variableX)();  // Supposed to work, but GCC does not like

using T = decltype(variableX); variableX.~T();

using X = some::random_namespace::X; variableX.~X();

using some::random_namespace::X; variableX.~X();  // Now in scope

真正的解决办法是使用std::destroy_at(std::addressof(variableX))

std::destroy_at(&variableX);  // Does not care about the name of the destructor