特征类中的成员函数“名称”? (通用适配器)
Posted
技术标签:
【中文标题】特征类中的成员函数“名称”? (通用适配器)【英文标题】:Member functions "name" in trait class? (generic adaptor) 【发布时间】:2013-01-22 08:47:37 【问题描述】:我已经使用 CRTP 实施了一项策略。该策略要求Base
类有一个名为 foo 的函数:
template<typename Base>
struct Policy<Base>
// ...
Base* b() return static_cast<Base*>(this);
void do() b()->foo();
;
我有一个名为Widget
的类使用我的策略。 Widget
实现 foo
一切都很好:
struct Widget : Policy<Widget>
// ...
void foo();
;
问题:我还有一个名为OldWidget
的类型,它在名为oldFoo
的函数中实现了foo
的功能:
struct OldWidget : Policy<OldWidget>
// ...
void oldFoo();
;
我不想想要修改 OldWidget(除了通过策略扩展它)。我不想想要使用AdaptedOldWidget
:
struct AdaptedOldWidget : OldWidget, Policy<AdaptedOldWidget>
void foo() oldFoo();
;
最好的办法是将我现有的 policy_traits
类扩展为:
template<typename T>
struct policy_traits ;
template<>
struct policy_traits<Widget>
// typedefs...
member_function_name = foo;
;
template<>
struct policy_traits<OldWidget>
// typedefs
member_function_name = oldFoo;
;
这样我就可以像这样实施政策:
template<typename Base>
struct Policy<Base>
// ...
Base* b() return static_cast<Base*>(this);
void do() b()->policy_traits<Base>::member_function_name();
;
有没有办法在 C++ 中实现类似的东西?
建议的解决方案:我可以执行以下操作:
template<typename Base>
struct Policy<Base> : Policy_Member_Traits<Base>
// ...
Base* b() return static_cast<Base*>(this);
void do() foo_wrapper();
;
template<typename T> struct Policy_Member_Traits ;
template<> struct Policy_Member_Traits<Widget>
void foo_wrapper() static_cast<T*>(this)->foo();
;
template<> struct Policy_Member_Traits<OldWidget>
void foo_wrapper() static_cast<T*>(this)->oldFoo();
;
希望有更好更简单的方法来实现这一点。
【问题讨论】:
您不能专门针对OldWidget
制定策略吗? (否则,在the pretty printer code 中有一个检测成员函数存在的特征示例。)
@KerrekSB 我不需要复制很多策略代码吗?我想重用策略中的所有内容,只需将函数名称替换为取决于类型的名称。我去看看漂亮的打印机代码,谢谢!
只是专门化调度(例如,制定另一个专门的“调度”策略)。
@KerrekSB 喜欢我刚刚提出的 Policy_Member_Traits 政策?没有更好的方法吗?它不是很干净,我需要一个 1) type_traits 类和 2) 每个类型的 member_function "traits" 类......这很奇怪。
好吧,在你的名字不好的void do()
(关键字警告!)中,你会说DispatchPolicy<Base>::dispatch_foo(b);
或类似的东西,而DispatchPolicy
模板只会包含相关的函数定义,专门个别案例。
【参考方案1】:
首先:所有函数的签名必须相同。然后你可以在policy_traits
中设置一个带有成员函数地址的静态成员,这样你以后就可以使用它(从你的Policy
模板)调用所需的函数。
typedef void (*void_memfn_type)();
template<>
struct policy_traits<Widget>
static void_memfn_type const member_function_name = &Widget::foo;
;
template<>
struct policy_traits<OldWidget>
static void_memfn_type const member_function_name = &OldWidget::oldFoo;
;
然后:
template<typename Base>
struct Policy<Base>
// ...
Base* b() return static_cast<Base*>(this);
void do() b()->policy_traits<Base>::(*member_function_name)();
;
【讨论】:
这看起来不错,但是直到 after 策略被实例化之前,小部件不是一个完整的类型,因此我无法获取成员函数 before 的指针实例化它。你试过这个吗?【参考方案2】:这是一个如何选择性地专门化的示例。首先,一些示例类:
#include <iostream>
struct Foo
void foo() const std::cout << "Foo::foo\n";
void bar() const std::cout << "Foo::foo\n";
;
struct Biz
void old_foo() const std::cout << "Fiz::old_foo\n";
void bar() const std::cout << "Fiz::foo\n";
;
struct Fiz
void foo() const std::cout << "Biz::foo\n";
void old_bar() const std::cout << "Biz::old_foo\n";
;
现在的特征:
template <typename T> struct Dispatch
static void foo(T const & x) x.foo();
static void bar(T const & x) x.bar();
;
template <> void Dispatch<Biz>::foo(Biz const & x) x.old_foo();
template <> void Dispatch<Fiz>::bar(Fiz const & x) x.old_bar();
下面是一个用法示例:
template <typename T> void dispatch(T const & x)
Dispatch<T>::foo(x);
Dispatch<T>::bar(x);
int main()
Foo f;
Biz b;
Fiz c;
dispatch(f);
dispatch(b);
dispatch(c);
【讨论】:
这似乎有效!我应该使用引用还是指针?我从 CRTP 调用调度,所以引用类似于dispatch(*b())
并且对象非常大。
其实我可以在 trait 中包含 dispatch,所以我会将问题标记为已回答。以上是关于特征类中的成员函数“名称”? (通用适配器)的主要内容,如果未能解决你的问题,请参考以下文章
在模板派生类中,为啥我需要在成员函数中使用“this->”来限定基类成员名称?