在它自己的指针上模板化 class?

Templating a class on its own pointer?

我想在它自己的指针上模板化 class。我该怎么做?

template <typename RefType, typename X>
class Foo {
 public:
  RefType ptr;
  X val;
};
typedef Foo<Foo*, int> Type1;
typedef Foo<std::list<Foo>::iterator itr, int> Type2;

基本上,RefType 是这样一种类型,RefType 上的 operator * 会给我一个 class Foo.

的实例

关于如何在 C++ 中执行此操作的任何想法?

编辑 :- 为我这样做的原因提供一些动力,我希望能够在下游客户端代码中执行此操作 :-

void clientFunc(Type1& x) {
  Type1 partner_x = *(x.partner);
}

事先不知道 x.partner 的类型。即 x.partner 可以是指向标准模板 class.

的指针或迭代器

这是一个非常晦涩的用例,我可以不用它,但代码看起来会更加优雅。

当然可以,但是由于您的 class 是模板化的,当您在 typedef 中声明指向它的指针时,您需要选择显式类型:

using Type1 = Foo<Foo<int*, int>*, int>;

你可以这样使用它:

Foo<int*, int> myFoo;
int val = 42;
myFoo.ptr = &val;
myFoo.val = 64;

Type1 myObj;
myObj.val = 1337;
myObj.ptr = &myFoo;

有测试:

std::cout << *(*myObj.ptr).ptr << std::endl; // access int* on a Foo*
std::cout << (*myObj.ptr).val << std::endl; // access int on a Foo*
std::cout << myObj.val << std::endl; // access int on self

打印:

42

64

1337


编辑

如果您希望始终有一个指向自身的指针,那么我会完全避开 RefType 模板:

template <typename X>
struct Foo {
  Foo* ptr; // ptr to Foo<X>
  X val;
};

并像这样使用它:

Foo<int> first;
first.val = 42;
first.ptr = &first; // now it refers to itself.


std::cout << first.val << std::endl;

// lets go nuts:
std::cout << first.ptr->ptr->ptr->ptr->val << std::endl;

这实际上与以前相同,除了现在 Foo 的指向实例将始终与其父实例一样被模板化。

你写的不能编译的原因是 Foo 不能在声明之外没有模板参数,即使是指针,例如 typedef Foo<Foo*, int> Type1;.[=22 中的 Foo* =]

如果你声明了 class,你可以递归地在那个类型定义中声明 Foo<RefType, X> 指针,但是你必须在某些时候有一个非 Foo* 的 RefType点让它工作。如:

typedef Foo<Foo<Foo<int*, int>*, int>*, int> Type1;

这可能不是您想做的事情。

同样的问题也适用于 typedef Foo<std::list<Foo>::iterator itr, int> Type2;。不能只说Foo,必须说whichFoo。这是个问题,因为模板参数可能会无限递归。

有很多潜在的方法可以解决这个问题。最简单的是修改 class 声明。这将起作用:

template<typename X>
class Foo
{
public:
    Foo* ptr;
    X val;
};
typedef Foo<int> Type1;

如果由于某种原因您无法更改模板,您可以使用 void* 并将其转换回合适的 Foo*:

template<typename RefType, typename X>
class Foo
{
public:
    RefType ptr;
    X val;
};
typedef Foo<void*, int> Type1;

int main( )
{
    Type1 test;
    Type1* test2 = static_cast< Type1* >( test.ptr );
}

然而,这显然更容易出错。

使用partial template specialization:

template <typename RefType, typename X>
class Foo
{
public:
    RefType ptr;
    X val;
};

template <typename X>
class Foo<void,X>
{
public:
    using TypeSelf = Foo;
    TypeSelf* ptr;
    X val;
};

typedef Foo<void,int> Type1;

Foo<void,int> 现在有成员 ptr,类型为 Foo<void,int>*

使用基数如何 class?

class Base {};

template <typename RefType, typename X>
class Foo : public Base
{
 public:
  RefType ptr;
  X val;
};
typedef Foo<Base*, int> Type1;

int main()
{
    Base* p = new Type1;
    Type1* pt = static_cast<Type1*>(p);
    pt->val = 3;
    pt->ptr = new Type1;
    (static_cast<Type1*>(pt->ptr))->val = 5;

    // delete etc.
    return 0;
}

您可以通过在 Baseclass 中引入适当的虚函数来跳过转换。

编辑

template<typename T>
class Base{
public:
    virtual Base<T>*& get_ptr() = 0;
    virtual T& get_val() = 0;
};

template <typename RefType, typename X>
class Foo : public Base<X>
{
 public:
  RefType ptr;
  X val;

  Base<X>*& get_ptr()
  {
    return ptr;
  }

  X& get_val()
  {
    return val;
  };

};
typedef Foo<Base<int>*, int> Type1;
typedef Base<int> BaseType;

int main()
{
    BaseType* p = new Type1;
    p->get_ptr() = new Type1;
    p->get_val() = 5;

    // delete etc.
    return 0;
}

颠覆的回答:

不是创建基 class,而是从 Foo 派生并使用它而不是 typedef。这类似于CRTP。

struct Type1 : public Foo<Type1 *, int> { };
struct Type2 : public Foo<std::list<Type2>::iterator, int> { };

您可以像使用 typedef 一样使用 Type1 和 Type2。