Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

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

I have an exceptional situation where I need to call the destructor of a class to clear union memory. We can not use an std::variant yet. The class in the union is template based and defined similar to:

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

    // Other useful functions.

  private:
    TYPE value;
}

Now we define different types with using:

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

In an earlier situation X was a derived classes from BaseTemplate.

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

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

In the old situation we were able to call the destructor like this:

X variableX;
variableX.~X();

In the new situation when using X = BaseTemplate<int>; is used this results in the error: expected class-name before ‘(’ token. So how do I call the destructor in this case?

Reproduction code:

#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();
}

>Solution :

variableX‘s destructor is called ~BaseTemplate(). However, if X is in scope and resolves to BaseTemplate<int>, it will also work as an alias for the destructor.

If X was not in scope:

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();

The real solution is to use std::destroy_at(std::addressof(variableX))

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

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading