English 中文(简体)
如何在变数中传递方法名称?
原标题:How to pass method name in variable?

在这方面,我有......。

struct Test {
  string foo() { return "bar"; }
};

#define callFn(obj,method) obj->method();

int main() {
  Test* t = new Test();
  cout << callFn(t,foo); // bar
  return 0;
}

......,这里也是我本愿通过的法典。

int main() {
  Test* t = new Test();
  string method = "foo";
  cout << callFn(t,method); // bar
  return 0;
}

是否可能?

最佳回答

你们可能希望像成员职能点一样:

typedef std::string (Test::*ptmf)();

#define CALL_MF(pobject, p) (((pobject)->*(p))())

int main()
{
    ptmf method = &Test::foo;
    Test * t = new Test;
    std::string result = CALL_MF(t, method);   // or directly: (t->*method)()
}

您可以创建集装箱,其成分为ptmf,以便在操作时管理不同的成员功能点:

std::map<int, ptmf> function_registry;

std::string call(int key, Test * t)
{
    auto it = function_registry.find(key);
    return (it != function_registry.end()) ? CALL_MF(t, *it) : "[ERROR]";
}
问题回答

你们能够这样做。 C++确实具有反射能力。

你们必须界定例如<代码>std:map,该地图向功能点人显示。

void foo(int x) { std::cout << "foo " << (x+3) << "
"; }
void bar(int x) { std::cout << "bar " << (x+5) << "
"; }

int main() {
    std::map<std::string, void (*)(int)> mapper;
    mapper["foo"] = &foo;
    mapper["bar"] = &bar;

    // ...

    mapper["foo"](42);
    mapper["bar"](42);
}

你可以做这样的事情,但由于C++缺乏思考能力,你必须做一些额外工作,才能做到这一点。

struct base {
  virtual void call_method( std::string const & ) = 0;
};

struct derived : public base {
  std::string foo( ) const {
    return "bar";
  }

  // More methods.

  void call_method( std::string const &p_name ) {
    if( p_name == "foo" ) {
      this -> foo( );
    }

    // More checks on method names.

    else {
      // Handle invalid function name.
    }
  }
};

这称为由数据驱动的接口,由你向物体发出指挥,并对它们以多变方式确认的指挥作出回应。 你可以改进我所显示的情况,从指挥部到职能点建立一个静态的未定地图,然后利用这一地图解决这一功能。 如果你能够避免这种职能分配,那是好的,因为与固定职能派遣相比,这种职能进展缓慢,而且由于打字可能会造成不正确的电话或错误,因此容易发生错误。 在某些情况下,也有可能获得回报价值,但这种下降也很容易。

EDIT:我要举一个更完整的例子,说明如何做到这一点。

#include <cassert>
#include <iostream>

#include <boost/bind.hpp>
#include <boost/blank.hpp>
#include <boost/variant.hpp>
#include <boost/function.hpp>

#include <boost/unordered_map.hpp>
#include <boost/assign/list_of.hpp>

// A base class that defines an interface to call methods by name
// and to access the list of methods.  We use a map of argument
// names to boost::variants to pass arguments to the functions.
// Right now we support only ints and strings, but we can expand
// this to other types if we want.  In particular, we can use
// boost::any to support arbitrary types, but it will be slow.
// Maybe that s not a big deal since function dispatch through
// named functions is slow anyway.

struct base {
  typedef boost::variant< boost::blank, int, std::string > argument_t;
  typedef boost::variant< boost::blank, int, std::string >   return_t;

  typedef boost::unordered_map< std::string, argument_t > param_map_t;

  typedef boost::function< return_t ( base *, param_map_t const & ) >
  method_t;

  typedef boost::unordered_map< std::string, method_t > method_map_t;

  return_t call_method(
      std::string const &p_method
    , param_map_t const &p_params = param_map_t( )
  )
  {
    method_map_t::const_iterator l_itr =
      get_methods( ).find( p_method );

    if( l_itr == get_methods( ).end( )) {
      // Handle undefined method identifier.
    }

    return l_itr -> second( this, p_params );
  }

  virtual method_map_t const &get_methods( ) const = 0;
};

// A trampoline object to elide the concrete type that
// implements the base interface and to provide appropriate
// casting.  This is necessary to force all functions in our
// method map to have the same type.

template< typename U >
base::return_t trampoline(
    base::return_t (U::*p_fun)( base::param_map_t const & )
  , base *p_obj
  , base::param_map_t const &p_param_map
)
{
  U *l_obj = static_cast< U* >( p_obj );
  return (l_obj ->* p_fun)( p_param_map );
}

// A derived type that implements the base interface and
// provides a couple functions that we can call by name.

struct derived : public base {
  static method_map_t const c_method_map;

  return_t foo( param_map_t const &p_params ) {
    std::cout << "foo" << std::endl;  return 1;
  }

  return_t bar( param_map_t const &p_params ) {
    std::cout << "bar" << std::endl;  return std::string( "bar" );
  }

  method_map_t const &get_methods( ) const {
    return c_method_map;
  }
};

// Construct map of method names to method pointers for derived.

base::method_map_t const derived::c_method_map = boost::assign::map_list_of
  ( "foo", boost::bind( &trampoline< derived >, &derived::foo, _1, _2 ))
  ( "bar", boost::bind( &trampoline< derived >, &derived::bar, _1, _2 ))
;

int main( ) {
  base *blah = new derived( );

  // Call methods by name and extract return values.

  assert( boost::get< int         >( blah -> call_method( "foo" )) == 1     );
  assert( boost::get< std::string >( blah -> call_method( "bar" )) == "bar" );

  // Iterate over available methods

  typedef base::method_map_t::const_iterator iterator;

  iterator l_itr = blah -> get_methods( ).begin( );
  iterator l_end = blah -> get_methods( ).end  ( );

  for( ; l_itr != l_end; ++l_itr ) {
    if( l_itr -> first == "foo" ) l_itr -> second( blah, base::param_map_t( ));
  }
}

产出如下:

foo
bar
foo

由于你可以看到,建立这一接口的工作范围很广,但增加实施接口的新类型非常容易。

这基本上是 Java1.5后可以利用的反思机制。

此处是C++反思的一个例子

rel=“nofollow” http://www.garret.ru/cppreflection/docs/reflect.html>





相关问题
Undefined reference

I m getting this linker error. I know a way around it, but it s bugging me because another part of the project s linking fine and it s designed almost identically. First, I have namespace LCD. Then I ...

C++ Equivalent of Tidy

Is there an equivalent to tidy for HTML code for C++? I have searched on the internet, but I find nothing but C++ wrappers for tidy, etc... I think the keyword tidy is what has me hung up. I am ...

Template Classes in C++ ... a required skill set?

I m new to C++ and am wondering how much time I should invest in learning how to implement template classes. Are they widely used in industry, or is this something I should move through quickly?

Print possible strings created from a Number

Given a 10 digit Telephone Number, we have to print all possible strings created from that. The mapping of the numbers is the one as exactly on a phone s keypad. i.e. for 1,0-> No Letter for 2->...

typedef ing STL wstring

Why is it when i do the following i get errors when relating to with wchar_t? namespace Foo { typedef std::wstring String; } Now i declare all my strings as Foo::String through out the program, ...

C# Marshal / Pinvoke CBitmap?

I cannot figure out how to marshal a C++ CBitmap to a C# Bitmap or Image class. My import looks like this: [DllImport(@"test.dll", CharSet = CharSet.Unicode)] public static extern IntPtr ...

Window iconification status via Xlib

Is it possible to check with the means of pure X11/Xlib only whether the given window is iconified/minimized, and, if it is, how?

热门标签