我想在自己的指针上模板化一个类。我该怎么做呢?
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 *
将为我提供类Foo的实例。
有关如何在C ++中执行此操作的任何想法?
编辑: - 为了解决我为什么这样做的动机,在下游的客户代码中,我希望能够做到: -
void clientFunc(Type1& x) {
Type1 partner_x = *(x.partner);
}
事先不知道x.partner的类型。即x.partner可以是指针或迭代器到标准模板类中。
这是一个非常模糊的用例,我可以不用它,但代码看起来会更优雅。
答案 0 :(得分:2)
使用基类怎么样?
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;
}
您可以通过在Base
类中引入适当的虚函数来跳过强制转换。
修改强>
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;
}
答案 1 :(得分:1)
当然有可能,但是由于你的类是模板化的,当你在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
如果您希望始终指向self,那么我将完全避开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
的实例将始终与其父实例相同。
答案 2 :(得分:1)
你编写的内容不能编译的原因是Foo不能在没有模板参数的情况下站在其声明之外,即使是指针,例如Foo*
中的typedef Foo<Foo*, int> Type1;
。
如果您按照自己的方式声明了类,则可以在该typedef中递归声明Foo<RefType, X>
个指针,但是您必须在某个时刻使用非Foo*
RefType才能使其工作。如:
typedef Foo<Foo<Foo<int*, int>*, int>*, int> Type1;
这可能不是你想要做的事情。
同样的问题适用于typedef Foo<std::list<Foo>::iterator itr, int> Type2;
。你不能只说Foo
,你必须说哪个 Foo
。这是一个问题,因为模板参数可能会有无限递归。
有很多可能的方法可以解决这个问题。最简单的是修改类声明。这将有效:
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 );
}
然而,这更容易出错。
答案 3 :(得分:1)
使用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>*
答案 4 :(得分:1)
转过jenas的答案:
不是创建基类,而是从Foo派生而不是使用typedef。这与CRTP类似。
struct Type1 : public Foo<Type1 *, int> { };
struct Type2 : public Foo<std::list<Type2>::iterator, int> { };
您可以像使用typedef一样使用Type1和Type2。