在它自己的指针上模板化 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;
}
您可以通过在 Base
class 中引入适当的虚函数来跳过转换。
编辑
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。
我想在它自己的指针上模板化 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;
}
您可以通过在 Base
class 中引入适当的虚函数来跳过转换。
编辑
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。