繁体   English   中英

我想推导C ++模板中的类型,从指向成员函数的指针开始

[英]I would like to deduce a type in C++ template, from a pointer to a member function

简洁版本:

不必总是输入:

auto function_pointer = &decorator<int, Foo, void &Foo::bar(int)>

我希望能够写

auto function_pointer = &decorator<void &Foo::bar(int)>

<void &Foo::bar(int) >中自动提取intFoo位置。


对于初学者,我有:

map<string, Object*> all_object_instances;

class Object {
public:
     Object(const string &name) { all_object_instances[name]=this; }
     virtual ~Object() { all_object_instances.erase(name); }
};

class Foo : public Object {
public:
     Foo(const string &name) : Object(name) {}
     void bar(int);
};

我需要一个函数,该函数将以某种修饰方式调用Foo :: bar(int) ,所以我这样写:

template <class Arg, class C, void C::*T(Arg)>
void decorator(const string &name, const string &s_arg)
{
    Arg a = my_convert(s_arg);
    C* c = dynamic_cast<C*>(all_object_instances[name]);
    (c->*T)(a);
}

所以我的主要代码必须看起来像这样:

   new Foo("MyFoo");
   ....
   auto saved_f = &decorator<int, Foo, void &Foo::bar(int)>;
   ....
   saved_f("MyFoo", "123");
   ....
   delete all_object_instances("MyFoo") // for symmetry

如果我只有一个模板参数,那就更好了:

saved_f = &decorator<void &Foo::bar(int)>;

并从参数中导出'Foo''int'

template <TEMPLATE MAGIC>
void decorator(const string &name, const string &s_arg)
{
    typedef ARG_MAGIC ARG;
    typedef CLASS_MAGIC C;

    Arg a = my_convert(s_arg);
    C* c = dynamic_cast<C*>(all_object_instances[name]);
    (c->*T)(a);
}

有没有这样的东西?

将函数作为参数传递将允许它被调用。 它可以简单地通过模板参数推导来推导。

在下面的示例中,我刚刚添加了一些通用性,将参数通过std::invoke传递,该参数可以执行自动指针到成员的调用。

template<class R,class C,class... Args>
auto get_class_type(R(C::*)(Args...))->C;

template<class F>
auto decorator(F f) {
  return [f=move(f)](auto const& name, auto const& arg) {
    using C=decltype(get_class_type(f));
    return std::invoke(move(f),
      dynamic_cast<C*>(all_object_instances[name]),
      my_convert(arg)
    );
  };
}

现在减少到:

auto saved_f = decorator(&Foo::bar);
saved_f("MyFoo", "123");

这需要std::invoke的C ++ 1y兼容编译器,可以在<functional>找到。 如果这不能为您编译,只需将其更改为:

auto c = dynamic_cast<C*>(all_object_instances[name]);
return (c->*move(f))(my_convert(arg));

如果您的目标是让template参数成为编译时间常数,那也是可能的。 在这种情况下,你将不得不使用宏,并传递一个integral_constantdecorator

#define decorator(mem_f) decorator_impl( integral_constant<decltype( mem_f ), mem_f>{} )

然后从类型中提取值:

template<class I>
auto decorator_impl( I ) {
  auto constexpr f = I::value;
  // same code as before...
}

在c ++ 17中,您应该能够编写:

template <auto m>
void decorator(const string &name, const string &s_arg);

具有所需的语法:

auto saved_f = &decorator<void &Foo::bar(int)>

代替

template <typename M, M m>
void decorator(const string &name, const string &s_arg);

带有语法

auto saved_f = &decorator<decltype(&Foo::bar), &Foo::bar>;

或您的版本。

然后,您需要一些函数特征来检索类和返回类型,例如:

template <typename> struct method_traits; 

template <typename Ret, typename Class, typename ... Args>
struct method_traits<Ret (Class::*)(Args...)>
{
    using ret_type = Ret;
    using classe_type = Class;
    using args_type = std::tuple<Args...>;
};

所以最后:

template <auto m>
void decorator(const string &name, const string &s_arg)
{
    using C = typename method_traits<decltype(m)>::class_type;
    using Arg = std::tuple_element_t<0, typename method_traits<decltype(m)>::args_type>;

    Arg a = my_convert(s_arg);
    C* c = dynamic_cast<C*>(all_object_instances[name]);
    (c->*T)(a);
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM