我应该如何在不使用 C++ 中的构造函数的情况下将值(而不是指针)转换为子类?

How should I cast a value (not a pointer) to a subclass without using a constructor in C++?

我有以下 classes 打算用作值类型(因为它们只存储整数):

class _foo_t
{
    friend _foo_t _make_foo();
private:
    int foo;
    _foo_t(int foo) : foo(foo) {}
protected:
    void *getptr() const; // defined in .cpp
};

template <typename T>
class foo_t : public _foo_t
{
public:
    T *getptr() const { return (T*)_foo_t::getptr(); }
    T &getref() const { return *(T*)_foo_t::getptr(); }
};

_foo_t _make_foo(); // defined in .cpp

template <typename T>
foo_t<T> make_foo()
{
    return _make_foo(); // What kind of cast do I need here?
}

class foo_t<T> 只是 _foo_t 的包装,为 getptrgetref 成员函数提供类型安全。同样,函数 make_foo() 只是 _make_foo<T>() 的包装器。由于 foo_t<T>_foo_t 的子 class 并且不添加任何字段并且没有虚拟成员,因此 foo_t<T> 对象看起来应该与 _foo_t 内存中的对象,我不想在这里调用构造函数的开销。如何安全、合规地将 _make_foo() 的 return 值从 _foo_t 转换为 foo_t<T>,而不产生任何开销?

编辑:

根据请求,这里是上面的一些示例用法:

class SomeObject { /* ... */ };

foo_t<SomeObject> obj = make_foo<SomeObject>();

new (obj.getptr()) SomeObject();
obj.getref().doSomething();

实际上,make_foo 必须采用大小参数或其他参数。

您可以概括您的 class 模板 foo_t 以能够在不依赖于 _foo_t 的情况下保存任何数据类型。您可以只使用:

template <typename T> class foo_t 
{
   public:
      char data[sizeof(T)];
      T *getptr() const { return (T*)data; }
      T &getref() const { return *(T*)data; }
};

template <typename T>
foo_t<T> make_foo()
{
   return foo_t<T>();
}

这是一个演示其用法的示例程序:

#include <iostream>
#include <new>

template <typename T> class foo_t 
{
   public:
      char data[sizeof(T)];
      T *getptr() const { return (T*)data; }
      T &getref() const { return *(T*)data; }
};

template <typename T>
foo_t<T> make_foo()
{
   return foo_t<T>();
}

struct Object1
{
   int a;
   int b;
};

struct Object2
{
   int a;
   double b;
};

struct Object3
{
   double a;
   double b;
};

int main()
{
   foo_t<Object1> obj1 = make_foo<Object1>();
   new (obj1.getptr()) Object1();
   obj1.getref().a = 10;
   obj1.getref().b = 20;
   std::cout << "Object1 - a:" << obj1.getref().a << ", b: " << obj1.getref().b << std::endl;

   foo_t<Object2> obj2 = make_foo<Object2>();
   new (obj2.getptr()) Object2();
   obj2.getref().a = 10;
   obj2.getref().b = 20.35;
   std::cout << "Object2 - a:" << obj2.getref().a << ", b: " << obj2.getref().b << std::endl;

   foo_t<Object3> obj3 = make_foo<Object3>();
   new (obj3.getptr()) Object3();
   obj3.getref().a = 10.92;
   obj3.getref().b = 20.35;
   std::cout << "Object3 - a:" << obj3.getref().a << ", b: " << obj3.getref().b << std::endl;

   return 0;
}

程序输出:

Object1 - a:10, b: 20
Object2 - a:10, b: 20.35
Object3 - a:10.92, b: 20.35

更新

鉴于您的评论,我认为您只需要:

template <typename T>
class foo_t : public _foo_t
{
   public:

      // Make sure you can use all of the base class
      // constructors in this class.
      using _foo_t::_foo_t;

      T *getptr() const { return (T*)_foo_t::getptr(); }
      T &getref() const { return *(T*)_foo_t::getptr(); }
};

template <typename T>
foo_t<T> make_foo()
{
   // Construct a foo_t<T> using a _foo_t and return it.
   return foo_t<T>(_make_foo());
}

How can I cast the return value of _make_foo() from _foo_t to foo_t safely, compliantly, and without creating any overhead?

你绝对不能 安全地转换 因为你不知道向下转换是有效的。但是,在这种特殊情况下,由于我们的派生类型与基类型大小相同,您可以使用:

template <typename T>
foo_t<T> make_foo()
{
    return static_cast<foo_t<T>&>(_make_foo());
}

也就是说,虽然这在 CRTP 世界中是有意义的,但我不确定它在这里是否有意义。