C++ 中方法和对象选择的静态多态性
Static Polymorphism for method and object selection in C++
尝试在没有基础 class 和虚拟调用的情况下获取编译时方法和对象选择。
情况如下:
struct A {
void f1()const { cout << "A::f1" << endl;}
void f2()const { cout << "A::f2" << endl;}
};
struct B {
void f1()const { cout << "B::f1" << endl;}
void f2()const { cout << "B::f2" << endl;}
};
class Holder {
A* _a = nullptr;
B* _b = nullptr;
public:
Holder(A* a): _a(a) {}
Holder(B* b): _b(b) {}
void f1()const {
if(_a) _a->f1();
else if(_b) _b->f1();
}
void f2()const {
if(_a) _a->f2();
else if(_b) _b->f2();
}
};
void f(const Holder& h) {
h.f1();
}
int main() {
B obj;
Holder h(&obj);
f(h);
}
http://coliru.stacked-crooked.com/a/4b5acec6866cfd4e
假设像A和B这样的class很少,但是像f1和f2这样的函数可能很多
Holder 需要在它持有的实际对象上调用函数,没有多态性,也不需要 A 和 B 的继承/共享接口。
寻找一种好的方法来做类似的事情:
class Holder {
A* _a = nullptr;
B* _b = nullptr;
public:
Holder(A* a): _a(a) {}
Holder(B* b): _b(b) {}
// below is pseudo code!
void call<function>()const {
if(_a)
_a->function(); // function is known in compile time, sort of...
else if(_b)
_b->function();
}
void f1()const { call<f1>(); }
void f2()const { call<f2>(); }
};
有什么想法吗?
- 宏?
- 模板?
- 其他技巧?
您可以使用变体。这将存储从 N 减少到 1 个指针加 1 个 int,并且除了 Holder
:
之外不需要更改任何内容
#include <boost/variant.hpp>
struct f1visitor
{
typedef void result_type;
template<typename T>
void operator()(T* const t) const { t->f1(); }
};
struct f2visitor
{
typedef void result_type;
template<typename T>
void operator()(T* const t) const { t->f2(); }
};
class Holder {
boost::variant<A*, B*> _ptr;
public:
Holder(A* a): _ptr(a) {}
Holder(B* b): _ptr(b) {}
void f1()const {
boost::apply_visitor(f1visitor(), _ptr);
}
void f2()const {
boost::apply_visitor(f2visitor(), _ptr);
}
};
使用足够新的 C++,您可以改用 std::variant
。
研究 John Zwinck 提出的解决方案并尝试减少对 boost::apply_visitor(f1visitor(), _ptr);
的重复调用的样板文件我已经取得了以下代码:
struct A {
void f1()const { cout << "A::f1" << endl;}
void f2(const std::string& s)const { cout << "Hello " << s << endl;}
int f3(int i, int j, int k)const { return i + j + k; }
};
struct B {
void f1()const { cout << "B::f1" << endl;}
void f2(const std::string& s)const { cout << "Shalom " << s << endl;}
int f3(int i, int j, int k)const { return i * j * k; }
};
class Holder {
boost::variant<A*, B*> _ptr;
public:
template<typename T> Holder(T* ptr): _ptr(ptr) {}
CREATE_DELEGATE_FUNCTION_0 (void, f1)
CREATE_DELEGATE_FUNCTION (void, f2, const std::string&)
CREATE_DELEGATE_FUNCTION (int, f3, int, int, int)
};
void f(const Holder& h) {
h.f1();
h.f2("world");
cout << h.f3(2, 3, 4) << endl;
}
int main() {
A obj1;
f(Holder(&obj1));
B obj2;
f(Holder(&obj2));
}
(需要注意的是,在编译时检查对 CREATE_DELEGATE_FUNCTION
的调用中的类型匹配)。
输出
A::f1
Hello world
9
B::f1
Shalom world
24
这个"magic"背后的宏:
#define NUM_ARGS(...) NUM_ARGS_(__VA_ARGS__, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0)
#define NUM_ARGS_(_10, _9, _8, _7, _6, _5, _4, _3, _2, _1, N, ...) N
#define CREATE_DELEGATE_FUNCTION_0(ret_type, name) \
ret_type name (void) const { \
return boost::apply_visitor([](auto* const t) \
{return t-> name ();}, _ptr); }
#define CREATE_DELEGATE_FUNCTION_1(ret_type, name, type1) \
ret_type name (type1 a) const { \
return boost::apply_visitor([&a](auto* const t) \
{return t-> name (a);}, _ptr); }
#define CREATE_DELEGATE_FUNCTION_2(ret_type, name, type1, type2) \
ret_type name (type1 a, type2 b) const { \
return boost::apply_visitor([&a, &b](auto* const t) \
{return t-> name (a, b);}, _ptr); }
#define CREATE_DELEGATE_FUNCTION_3(ret_type, name, type1, type2, type3) \
ret_type name (type1 a, type2 b, type3 c) const { \
return boost::apply_visitor([&a, &b, &c](auto* const t) \
{return t-> name (a, b, c);}, _ptr); }
#define M_CONC(A, B) M_CONC_(A, B)
#define M_CONC_(A, B) A##B
#define CREATE_DELEGATE_FUNCTION(ret_type, name, ...) \
M_CONC(CREATE_DELEGATE_FUNCTION_, NUM_ARGS(__VA_ARGS__)) (ret_type, name, __VA_ARGS__)
尝试在没有基础 class 和虚拟调用的情况下获取编译时方法和对象选择。
情况如下:
struct A {
void f1()const { cout << "A::f1" << endl;}
void f2()const { cout << "A::f2" << endl;}
};
struct B {
void f1()const { cout << "B::f1" << endl;}
void f2()const { cout << "B::f2" << endl;}
};
class Holder {
A* _a = nullptr;
B* _b = nullptr;
public:
Holder(A* a): _a(a) {}
Holder(B* b): _b(b) {}
void f1()const {
if(_a) _a->f1();
else if(_b) _b->f1();
}
void f2()const {
if(_a) _a->f2();
else if(_b) _b->f2();
}
};
void f(const Holder& h) {
h.f1();
}
int main() {
B obj;
Holder h(&obj);
f(h);
}
http://coliru.stacked-crooked.com/a/4b5acec6866cfd4e
假设像A和B这样的class很少,但是像f1和f2这样的函数可能很多
Holder 需要在它持有的实际对象上调用函数,没有多态性,也不需要 A 和 B 的继承/共享接口。
寻找一种好的方法来做类似的事情:
class Holder {
A* _a = nullptr;
B* _b = nullptr;
public:
Holder(A* a): _a(a) {}
Holder(B* b): _b(b) {}
// below is pseudo code!
void call<function>()const {
if(_a)
_a->function(); // function is known in compile time, sort of...
else if(_b)
_b->function();
}
void f1()const { call<f1>(); }
void f2()const { call<f2>(); }
};
有什么想法吗?
- 宏?
- 模板?
- 其他技巧?
您可以使用变体。这将存储从 N 减少到 1 个指针加 1 个 int,并且除了 Holder
:
#include <boost/variant.hpp>
struct f1visitor
{
typedef void result_type;
template<typename T>
void operator()(T* const t) const { t->f1(); }
};
struct f2visitor
{
typedef void result_type;
template<typename T>
void operator()(T* const t) const { t->f2(); }
};
class Holder {
boost::variant<A*, B*> _ptr;
public:
Holder(A* a): _ptr(a) {}
Holder(B* b): _ptr(b) {}
void f1()const {
boost::apply_visitor(f1visitor(), _ptr);
}
void f2()const {
boost::apply_visitor(f2visitor(), _ptr);
}
};
使用足够新的 C++,您可以改用 std::variant
。
研究 John Zwinck 提出的解决方案并尝试减少对 boost::apply_visitor(f1visitor(), _ptr);
的重复调用的样板文件我已经取得了以下代码:
struct A {
void f1()const { cout << "A::f1" << endl;}
void f2(const std::string& s)const { cout << "Hello " << s << endl;}
int f3(int i, int j, int k)const { return i + j + k; }
};
struct B {
void f1()const { cout << "B::f1" << endl;}
void f2(const std::string& s)const { cout << "Shalom " << s << endl;}
int f3(int i, int j, int k)const { return i * j * k; }
};
class Holder {
boost::variant<A*, B*> _ptr;
public:
template<typename T> Holder(T* ptr): _ptr(ptr) {}
CREATE_DELEGATE_FUNCTION_0 (void, f1)
CREATE_DELEGATE_FUNCTION (void, f2, const std::string&)
CREATE_DELEGATE_FUNCTION (int, f3, int, int, int)
};
void f(const Holder& h) {
h.f1();
h.f2("world");
cout << h.f3(2, 3, 4) << endl;
}
int main() {
A obj1;
f(Holder(&obj1));
B obj2;
f(Holder(&obj2));
}
(需要注意的是,在编译时检查对 CREATE_DELEGATE_FUNCTION
的调用中的类型匹配)。
输出
A::f1
Hello world
9
B::f1
Shalom world
24
这个"magic"背后的宏:
#define NUM_ARGS(...) NUM_ARGS_(__VA_ARGS__, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0)
#define NUM_ARGS_(_10, _9, _8, _7, _6, _5, _4, _3, _2, _1, N, ...) N
#define CREATE_DELEGATE_FUNCTION_0(ret_type, name) \
ret_type name (void) const { \
return boost::apply_visitor([](auto* const t) \
{return t-> name ();}, _ptr); }
#define CREATE_DELEGATE_FUNCTION_1(ret_type, name, type1) \
ret_type name (type1 a) const { \
return boost::apply_visitor([&a](auto* const t) \
{return t-> name (a);}, _ptr); }
#define CREATE_DELEGATE_FUNCTION_2(ret_type, name, type1, type2) \
ret_type name (type1 a, type2 b) const { \
return boost::apply_visitor([&a, &b](auto* const t) \
{return t-> name (a, b);}, _ptr); }
#define CREATE_DELEGATE_FUNCTION_3(ret_type, name, type1, type2, type3) \
ret_type name (type1 a, type2 b, type3 c) const { \
return boost::apply_visitor([&a, &b, &c](auto* const t) \
{return t-> name (a, b, c);}, _ptr); }
#define M_CONC(A, B) M_CONC_(A, B)
#define M_CONC_(A, B) A##B
#define CREATE_DELEGATE_FUNCTION(ret_type, name, ...) \
M_CONC(CREATE_DELEGATE_FUNCTION_, NUM_ARGS(__VA_ARGS__)) (ret_type, name, __VA_ARGS__)