考虑这个人为的例子:
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
来解决此问题?我可以使用任何标准库工具吗?
答案 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>()