【问题标题】:Passing a member function via std::function通过 std::function 传递成员函数
【发布时间】:2015-11-06 20:09:05
【问题描述】:

我想检查一个数据字段是否有效(有效表示不为空且未填充默认值)

基本上

return (!connector->IsNull(field_id) and connector->Get<type>Default(field_id, default_value))

但“类型”可以是多种类型(字符串、int64 等)中的一种,因此有 5-6 种不同的函数。我为它创建了一个辅助函数,我正在尝试传入相关的 GetDefault...

template<typename T> bool IsValidField(std::unique_ptr<Connector>& connector, const std::function<T(int, T)> &GetDefault, int field_id, T default_value){
  return (!connector->IsNull(field_id) && connection->GetDefault(field_id, default_value) != default_value);
}

我正在调用辅助函数......

IsValidField(connector, connector->GetStringWithDefault,20,"")

我收到错误“错误:必须调用对非静态成员函数的引用 " 因为 GetStringWithDefault 不是静态函数,我该如何解决这个问题?

或者,有没有办法让它稍微不那么尴尬?

【问题讨论】:

    标签: c++ c++11 std-function


    【解决方案1】:

    两种可能的解决方案,一种是使用std::bind,另一种是使用std::mem_fn


    对于使用 std::bind 的解决方案,它可能看起来像

    template<typename T, typename F>
    bool IsValidField(std::unique_ptr<Connector>& connector, F GetDefault,
                      int field_id, T default_value)
    {
        return (!connector->IsNull(field_id) &&
                GetDefault(field_id, default_value) != default_value);
    }
    

    然后这样称呼它

    IsValidField(
    
    IsValidField(connector,
                 std::bind(&ClassForConnector::GetStringWithDefault, _1, _2),
                 20,"");
    

    对于std::mem_fn 解决方案,可能类似于

    template<typename T, typename F>
    bool IsValidField(std::unique_ptr<Connector>& connector, F GetDefault,
                      int field_id, T default_value)
    {
        return (!connector->IsNull(field_id) &&
                GetDefault(connector, field_id, default_value) != default_value);
    }
    

    然后这样称呼它

    IsValidField(connector,
                 std::mem_fn(&ClassForConnector::GetStringWithDefault),
                 20,"");
    

    【讨论】:

    • 是否有可能以某种方式删除“连接器”参数?
    • @Narabhut 除非您删除 connector-&gt;IsNull(field_id) 检查。
    【解决方案2】:

    也许不是最简洁,但最简单的解决方案似乎是将所有内容包装到 lambda 中:

    IsValidField(connector, [connector]() -&gt; T {return connector-&gt;GetStringWithDefault(20, "")})

    但是你需要相应地调整IsValidField签名。

    【讨论】:

    • 为此,我什至不需要该功能,对吧?如果它们是这样的一个衬垫,我想我可以制作 4-5 个。
    【解决方案3】:

    这里发生了两件事。一次只做一件事。

    清理如何调用GetStringWithDefault,这样你就可以在不知道函数名的情况下根据它的类型得到一些东西,如下:

    namespace impl {
      template<class T, T Connector::*Method(int, T const&)>
      struct GetWithDefault {
        T operator()(Connector const& connector, int id, T const& default) const {
          return (connector.*Method)(id, default);
      };
    }
    
    template<class T>
    struct GetWithDefault;
    
    template<>struct GetWithDefault<std::string>:
      impl::GetWithDefault<std::string, &Connector::GetStringWithDefault>
    {};
    

    对每种支持的类型重复。现在,GetWithDefault&lt;Bob&gt;{}(*connector, id, default_bob) 做你想做的事。

    现在是空版本:

    template<class T>
    bool IsValidField(Connector const& connector, int id, T const& default_value) {
        return !connector.IsNull(id) && (GetWithDefault<T>{}(connector, id, default_value)!=default_value);
      }
    };
    

    这会将T 和gettor 之间的关联转移到帮助器类型GetWithDefault,我们通过显式特化(有点像特质类)来实现它。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-01-18
      • 1970-01-01
      • 2014-02-11
      • 2023-03-31
      • 1970-01-01
      • 1970-01-01
      • 2015-03-04
      • 2012-08-22
      相关资源
      最近更新 更多