【问题标题】: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&lt;Base&gt;::dispatch_foo(b);或类似的东西,而DispatchPolicy模板只会包含相关的函数定义,专门个别案例。

标签: c++ adapter policy traits


【解决方案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,所以我会将问题标记为已回答。
猜你喜欢
  • 1970-01-01
  • 2023-04-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-12-12
  • 2015-10-02
  • 2022-11-27
相关资源
最近更新 更多