按类型

时间:2016-07-12 21:09:25

标签: c++ c++11 c++14

考虑这个人为的例子:

template<typename Fn, typename Iter, typename T>
void funny_transform(Iter first, Iter last, vector<T>& v)
{
    transform(first, last,
              back_inserter(v),
              Fn());
}

通常我们会直接传递functor对象,但是这个例子是为了模拟许多STL容器的行为而设计的。例如,std::map可以使用比较器的类型并默认构造它,而不是直接获取比较器对象。 (我的实际用例是一些无状态仿函数类。由于该类是无状态的,我只能传入类型。)

问题在于std::mem_fn。如果我尝试做类似的事情:

auto get_size = mem_fn(&string::size);

vector<string> v1 = { ... };
vector<string::size_type> v2;

funny_transform<decltype(get_size)>(v1.cbegin(), v1.cend(), v2);  // oops

这不会起作用,因为decltype(get_size)(无论它是什么)没有默认构造函数。虽然奇怪的是它有复制和移动构造函数。由于完全相同的原因,切换到简单的lambda也不会起作用。

我是否必须编写自己的仿函数struct来解决此问题?我可以使用任何标准库工具吗?

2 个答案:

答案 0 :(得分:1)

template<class F>
F& magic_store(F* f) {
  static const F r=std::move(*f);
  return r;
}
template<class F>
struct stateless_t{
  stateless_t(F&&f){ magic_store<F>(&f); }
  stateless_t()=default;

  template<class...Args>
  decltype(auto) operator()(Args&&...args)const{
    return magic_store<F>(nullptr)(std::forward<F>(f));
  }
};
template<class F>
stateless_t<F> make_stateless(F f){ return std::move(f); }

现在你可以做到

auto get_size = make_stateless([](auto&s){return s.size();});

vector<string> v1 = { ... };
vector<string::size_type> v2;

funny_transform<decltype(get_size)>(v1.cbegin(), v1.cend(), v2);  // works

请注意,这是一个可怕的黑客,但标准的合法。它很容易被滥用,很容易非本地搞砸。只能使用已经无状态的lambda。永远任何其他。

在C ++ 17中你可以写:

template<auto F>
struct stateless_invoker{
  template<class...Args>
  decltype(auto) operator()(Args&&...args) const{
    return std::invoke( F, std::forward<Args>(args)... );
  }
};

给你:

using get_size = stateless_invoker<&std::string::size>;

vector<string> v1 = { ... };
vector<string::size_type> v2;

funny_transform<get_size>(v1.cbegin(), v1.cend(), v2);  // works

这不那么hacky。这可以在C ++ 11中重现,但很难看。

答案 1 :(得分:0)

根据@Yakk的想法,C ++ 14中的简单解决方法可能如下所示:

sql_query1 = RealEstateAgentAssignmentStatus.joins(:developer_referrals)
                                            .where(:assignment_status => ['Pending Eligibility Check', 'Completed Eligibility Check'])
                                            .group(:assignment_status)
                                            .order(:rank)
                                            .all

然后:

template<typename PMF, PMF pmf>
struct my_mem_fn_t {
    template<typename... Args>
    constexpr decltype(auto) operator()(Args&&... args) const
        noexcept(noexcept(std::mem_fn(pmf)(std::forward<Args>(args)...)))
    {
        return std::mem_fn(pmf)(std::forward<Args>(args)...);
    }
};

// well, if you really want to use macro
#define my_mem_fn(pmf) my_mem_fn_t<decltype(pmf), pmf>()