我想从指向成员函数的指针推断出C ++模板中的一个类型

时间:2016-11-01 18:12:08

标签: c++

简短版本:

而不是总是输入:

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

我希望能够写出

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

int&gt;自动提取Foo<void &Foo::bar(int)

对于初学者我有:

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);
}

有没有这样的东西?

2 个答案:

答案 0 :(得分:0)

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

在下面的示例中,我刚刚添加了一些通用性,通过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));

如果你的目标是让模板参数成为编译时常量,那也是可能的。在这种情况下,您必须使用宏并将integral_constant传递给decorator

#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...
}

答案 1 :(得分:-1)

在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);
}