我正在为我们在其他代码中定义的一堆类编写一个通用包装类。我试图弄清楚C ++中是否有一种方法可以编写一个可以将模板参数存储为变量的模板化类。以下是我希望看到的工作示例:
template < class C > class generic {
public:
C obj; // used for custom type processing
template < class T > T other; // <- changeable variable (or something)
template < class T > setOther() { // Function to change variable
// code to change variable type, or set type
}
void doSomethingWithOther() {
// do some processing for other, like call
// specific member function or something
(((other*)obj)->*SomeGenericMethod)()
}
}
int main(int argc, char **argv) {
Bar bObj;
generic<Foo> fObj;
fObj.setOther<Bar>();
fObj.doSomethingWithOther();
return 0;
}
我知道上面的代码不会因为很多原因而编译,但我的问题更多的是关于功能。有没有什么方法可以将模板参数存储为变量(或使用函数或其他东西),然后可以将其用作类型说明符?如果没有标准方式,来自SO社区的任何想法可能会产生我想要的结果吗?
请不要Boost或其他第三方图书馆,我试图将其保留为“STL”(C99)。
我的另一个想法是使用默认特化:
template < class C, class T = void* > class generic {
public:
C obj;
T other;
// ... more code
}
但在这种情况下,假设我们有以下内容:
class Test1 {
public:
generic<Foo> *G1;
generic<Foo, Bar> *G2;
};
如果我想稍后更改G1的类型以进行其他处理,我可以说如下:
G1 = new generic<Foo, Bar>(); // compile error, different types
但是,这会导致编译错误,因为指向的两种类型具有不同的类型(G1类型为generic< C >
,另一类型类型为generic< C, T >
,即使模板类{{1} }默认为T
。
对于这篇长篇文章感到抱歉,我试图尽可能清楚地表达我对此代码的意图。同样,请随时在我的任何陈述中纠正我(漫长的日子=对我来说脑活动减少)
提前感谢您对此事的任何帮助。
编辑1:
为了澄清,void*
数据成员只是为了表明我希望该成员持有类类型。这是因为我们的代码有其他类的成员调用实例化成员函数。如果我要调用另一个类的成员函数,我将收到编译错误。
不幸的是,我不能使用任何C ++ 0x功能,因为我们的嵌入式编译器较旧,不支持0x功能集。否则这将是明显的解决方案。
我基本上必须构建一个委托类型的系统,以便实例化的类可以从内部调用其他实例类的成员,并且被调用的成员函数将具有内存空间并访问other
指针< / p>
示例:
this
在class Foo {
public:
Delegate other;
}
class Bar {
public:
void SomeFunction() {
std::cout << "hello from Bar::SomeFunction, data = " << data << std::endl;
}
int data;
}
int main() {
Foo F;
Bar B;
B.data = 10;
F.other = Delegate::attach<Bar>(&Bar::SomeFunction, &B);
// Delegate::attach is defined as
// template < class T > Delegate attach(void (T::*fnPtr)(void*), T *obj)
F.other();
}
类的上述示例void operator()()
中,通过Delegate
调用其他成员函数。如果以这种方式调用,该函数无法访问它的成员数据(不知道(*fnPtr)()
指针)。如果调用传递引用的对象(即this
),则该函数现在可以访问成员数据。
我正在尝试通过指定一个通用的(*fnPtr)(obj)
对象来解决这个问题,然后可以来回传播,因为class type
可以附加到任何成员。
答案 0 :(得分:4)
目前尚不清楚您试图解决的问题是什么。在您的代码中,class C
的目的是什么?无论如何,这里猜测你想要什么。使用从具有虚拟implementation
的公共基类派生的基础模板类interface
,并使generic
类保存指向该interface
的指针。
class generic {
class interface {
public:
virtual ~interface(){}
virtual void SomeGenericMethod()=0;
};
template <class T>
class implementation: public interface {
T data;
public:
implementation(const T& d) :data(d) {}
virtual void SomeGenericMethod()
{return data.SomeGenericMethod();}
};
public:
std::unique_ptr<interface> data;
template < class T > void setOther(const T& other) {
data.reset(new implementation<T>(other));
}
void doSomethingWithOther() {
data->SomeGenericMethod();
}
};
int main(int argc, char **argv) {
generic fObj;
Bar bObj;
fObj.setOther(bObj);
fObj.doSomethingWithOther();
return 0;
}
答案 1 :(得分:0)
如果在编译时不知道确切的类型,则不能将其编码为模板参数。这些必须在编译时知道,之后不能更改。查看Boost.Any
(任何可能的类型)或Boost.Variant
(多种已知类型)以获取可以帮助您的示例。 any
可以通过合理的努力来实现,variant
并非如此。鉴于您对C ++模板的了解,您可能不应该在没有真正了解boost中的代码的情况下尝试实现,而不是冒犯。
答案 2 :(得分:0)
听起来你的主要目标是调用other
的一些成员函数。
如果是这种情况,您甚至不需要other
,而只需要封装调用的仿函数。例如。使用C ++ 11或TR1:
template <class C> struct A {
C obj;
std::function<void ()> op;
void f() {
// ...
op();
}
};
struct B {
void g() { std::cout << "moo" << std::endl; }
};
int main() {
A<int> a;
B b;
a.op = std::bind(&B::g, &b);
a.f();
}