繁体   English   中英

模板成员函数指针的std :: map

[英]std::map of template member function pointers

我正在阅读此问题的答案,并试图找出如何在std::map存储模板成员函数指针c ++ 11。

class A {
  template<typename T>
  using MFP  = T (A::*)();

  std::map <string, MFP> fmap;

  template<typename T>
  T f() { return 1; }

  template<typename T>
  T g() { return 1.0f; }

  A() {
    fmap.insert(std::make_pair( "f", &A::f));
    fmap.insert(std::make_pair( "g", &A::g));
  }

  template<typename T>
  T Call(const string & s) {
    MFP fp = fmap[s];
    return (this->*fp)();
  }
};

类型别名可以编译,但是当我在std::map声明中使用它时,出现以下错误:

error: type/value mismatch at argument 2 in template parameter list for ‘template<class _Key, class _Tp, class _Compare, class _Alloc> class std::map’
 std::map<std::string, MFP> fmap;

有任何想法吗?

正如Sam所注意到的, MFP是一个模板,而std::map的第二个模板参数需要一个类型。 因此,在使用函数指针填充映射之前,您需要获取实际的类型。 让我为这种情况提出最直接的方法-模板类。 使用它,您将需要在对象实例化上列出所有所需的返回类型,但是您将能够使用这些类型中的任何一个进行Call 我将使用std::function代替指针,但是您可以轻松地回滚到函数指针。

首先,我们不知道该类用户将需要多少种类型,因此让我们使其可变。 由于map需要完整的类型,因此我们需要一堆地图-每个类型一个。 最常见的获取方法是元组,在我们的案例中需要扩展包。 使用元组,我们可以在编译时搜索所需的映射,然后在运行时按名称搜索其中的函数。 看一下带有解释的代码:

template<typename ...Types>
class B {
private:

  // Template alias for std::function.
  template<typename T>
  using MFP = std::function<T()>;

  /* Tuple of maps from std::string to MFP for all types
     in Types parameter pack. */
  std::tuple<std::map<std::string, MFP<Types>>...> fmap;

  template<typename T>
  T f() { return 2.5; }

  template<typename T>
  T g() { return 1.0f; }

  // Call implementation with compile-time pattern matching.
  // T is return type, U is current matching type
  template<typename T, size_t idx, typename U, typename ...Ts>
  struct CallImpl {
    static T callImpl(B* this_ptr, const std::string & s) {
      /* If we exhausted Ts pack, we have no proper instance for
         requested return type. Let's print a human-readable
         compilation error message. */
      static_assert((sizeof ... (Ts)) > 0,
        "Requested return type not found.");
      /* Otherwise discard U, increment tuple index
         and try the next type. */
      return CallImpl<T, idx + 1, Ts...>::callImpl(this_ptr, s);
    }
  };

  /* This partial specialization is called when return
   * type (T in above declaration) matches
   * stored type (U in above declaration). */
  template<typename T, size_t idx, typename ...Ts>
  struct CallImpl<T, idx, T, Ts...> {
    static T callImpl(B* this_ptr, const std::string & s) {
      /* First, get the map from tuple by index.
         This operation is either always valid in runtime or does not compile.
         Next, get function object from map. It may fail in runtime
         if user passed invalid string, so consider using map::at
         or add any other sensible logic for this case. */
      return std::get<idx>(this_ptr->fmap)[s]();
    }
  };

public:

  B() {
    /* Populate map with objects. Ellipsis in the last line
       expands Types as needed. */
    fmap = std::make_tuple(std::map<std::string, MFP<Types>>{
      {"f", std::bind(std::mem_fn(&B::f<Types>), this)},
      {"g", std::bind(std::mem_fn(&B::g<Types>), this)}
    }...);
  }

  template<typename T>
  T Call(const std::string & s) {
    /* Start pattern matching with zero index. */
    return CallImpl<T, 0, Types...>::callImpl(this, s);
  }
};

用法:

int main() {

    B<int, float, short> a; // Provides int, float and short return types.
    std::cout << a.Call<int>("f") << std::endl; // Prints 2, which is 2.5 casted to int.
    std::cout << a.Call<float>("f") << std::endl; // Prints 2.5

    // Compilation error with "Requested type not found." message among others.
    std::cout << a.Call<double>("f") << std::endl; 
}

一些注意事项:

  • f声明中的2.5是double常量,但在B<int, float> a;未列出double B<int, float> a; ,这会导致a.Call<double>("whatever")编译错误。
  • 代码Call方法和callImpl的功能short不产生可言,因为我们不实例化。

std::map的第二个模板参数是std::map值的类或类型。 例如:

std::map<std::string, int> mapsi;

第二个模板参数是整数类型int

您的声明:

std::map <string, MFP> fmap;

MFP不是类或类型。 MFP是另一个模板。 这等效于编写:

std::map <string, template<typename T> T (A::*)()> fmap;

这没有任何意义。 因此,编译错误。

您可以这样写:

std::map <string, MFP<int>> fmap;

要么

std::map <string, MFP<std::string>> fmap;

MVP<int>MFP<std::string>是实际类型,是实际类,因此您可以将它们放入映射中。 您不能将模板放入地图中,因为模板不是实际的类或类型。

template<typename T>
T f() { return 1; }

template<typename T>
T g() { return 1.0f; }

您显然相信这些是成员函数。 他们不是。 它们是成员模板。 没有指向成员模板的指针,只有指向成员函数的指针。

暂无
暂无

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

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