我需要用相当大的类替换代码中的动态多态,并且我遇到了CRTP +可变参数模板设计的问题。
为了说明,我在下面提供了玩具问题。
有一个动态多态类,以便使用以下接口:
int main() {
Loop loop;
Add add ;
loop.set(add);
loop.run();
Sub sub ;
loop.set(sub);
}
当然,Sub
和Add
派生自基类Operation
,op(double & v)
是虚拟方法。
由于其他原因,我需要保留此接口,同时通过静态多态更改动态,这是我的解决方案,直到现在:
template <typename T> class Operation {
public:
double d=1.;
void op(double & d) { static_cast<T*>(this)->op(d);}
};
class Add final: public Operation<Add> {
public: void op(double & v) { v += d; }
};
class Sub final: public Operation<Sub> {
public: void op(double & v) { v -= d; }
};
和Loop
类:
template <typename... Types>
class MetaLoop {
public:
double d = 0 ;
template <typename T> void set(T & t) {
std_cxx17::get<std::vector<T*> >(data).push_back(&t) ;
}
template <typename T> void run() {
for (auto j = 0; j<2E9 ; ++j)
std_cxx17::get<std::vector<T*> >(data).back()->op(d);
std::cout << d << std::endl;
}
private:
std::tuple<std::vector<Types*>... > data ;
};
typedef MetaLoop<Add,Sub> Loop ;
std_cxx17::get<T*>(data)
是对按类型选择元组中元素的方法的调用,类似于this post
然而,这个解决方案需要几乎我想要的接口,除了需要向run()
提供模板参数,即run<Add>
和run<Sub>
以及需要在Add
Sub
和MetaLoop
到typedef MetaLoop<Add,Sub> Loop
我想知道是否可以在不使用宏的情况下:
Operation<T>
课程注册到MetaLoop
(即自动拨打typedef Metaloop<...operations...>
)run
方法。 (即拨打run()
而不是run<Add>()
)请记住,我知道我可以使用其他几种架构,但我还有许多其他限制。这只是一个玩具问题,可以举例说明。
提前致谢!
编辑1:
问题2已经回答了!见这里:http://coliru.stacked-crooked.com/a/e68ea7faabba3e40
答案 0 :(得分:0)
您可以键入 - 删除您的类型,如下例所示:
#include <iostream>
#include <vector>
#include <utility>
template<typename T>
struct Operation {
void op(double &d) { static_cast<T*>(this)->op(d) ; }
double d{1};
};
struct Add: Operation<Add> {
void op(double &v) { v += d; }
};
struct Sub: Operation<Sub> {
void op(double &v) { v -= d; }
};
class Loop {
using Fn = void(*)(double &, void *);
template<typename T>
static void op(double &d, void *op) {
static_cast<T*>(op)->op(d);
}
public:
template<typename T>
void set(T &t) {
data.emplace_back(&op<T>, &t);
}
void run() {
auto &p = data.back();
for(auto j = 0; j < 10; ++j) {
p.first(d, p.second);
}
std::cout << d << std::endl;
}
private:
std::vector<std::pair<Fn, void*>> data;
double d = 0;
};
int main() {
Loop loop;
Add add;
loop.set(add);
loop.run();
Sub sub;
loop.set(sub);
// ...
}
另请注意,在这种情况下,CRTP惯用法是无用的,您可以删除模板类Operation
。
只需定义Add
和Sub
,如下所示:
struct Add {
void op(double &v) { v += d; }
double d{1};
};
struct Sub {
void op(double &v) { v -= d; }
double d{1};
};
如果您想区分Add
和Sub
并提供不同的算法,可以使用专业化。
举个例子:
class Loop {
using Fn = void(*)(double &, void *);
template<typename T>
static void op(double &d, void *op);
public:
template<typename T>
void set(T &t) {
data.emplace_back(&op<T>, &t);
}
void run() {
auto &p = data.back();
for(auto j = 0; j < 10; ++j) {
p.first(d, p.second);
}
std::cout << d << std::endl;
}
private:
std::vector<std::pair<Fn, void*>> data;
double d = 0;
};
template<>
void Loop::op<Add>(double &d, void *op) {
Add *add = static_cast<Add*>(op);
// do whatever you want with add
add->op(d);
}
template<>
void Loop::op<Sub>(double &d, void *op) {
Sub *sub = static_cast<Sub*>(op);
// do whatever you want with sub
sub->op(d);
}
请注意,该解决方案符合问题中列出的所有要求,并且与OP提供的main
一起使用。