C++ 按类型构造std::mem_fn

C++ 按类型构造std::mem_fn,c++,c++11,c++14,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()); } 这将不起作用,因为decltype(get\u size)(不

考虑这个人为的例子:

template<typename Fn, typename Iter, typename T>
void funny_transform(Iter first, Iter last, vector<T>& v)
{
    transform(first, last,
              back_inserter(v),
              Fn());
}
这将不起作用,因为
decltype(get\u size)
(不管它是什么)没有默认构造函数。奇怪的是,它有复制和移动构造函数。出于完全相同的原因,切换到简单的lambda也不起作用

我是否必须编写自己的functor
struct
来解决这个问题?是否有任何标准库工具可供我使用?

模板
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); }
F&magic_商店(F*F){ 静态常数fr=std::move(*F); 返回r; } 模板 无状态结构{ 无状态存储(F&&F){magic_存储(&F);} 无状态_t()=默认值; 模板 decltype(自动)运算符()(Args&&…Args)常量{ 返回幻方存储(nullptr)(标准::转发(f)); } }; 模板 无状态\u t使\u无状态(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
auto get_size=make_无状态([](auto&s){return s.size();});
向量v1={…};
矢量v2;
有趣的_变换(v1.cbegin(),v1.cend(),v2);//作品
请注意,这是一个可怕的黑客,但标准的法律。它很容易被滥用,也很容易在非本地搞砸。仅对已无状态的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)... );
  }
};
模板
结构无状态调用程序{
模板
decltype(自动)运算符()(Args&&…Args)常量{
返回std::invoke(F,std::forward(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
使用get\u size=stateless\u调用程序;
向量v1={…};
矢量v2;
有趣的_变换(v1.cbegin(),v1.cend(),v2);//作品

这就不那么麻烦了。这可以在C++11中复制,但很难看。

基于@Yakk的想法,C++14中的一个简单解决方案可以如下所示:

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>()
模板
结构我的记忆{
模板
constexpr decltype(auto)运算符()(Args&&…Args)const
noexcept(noexcept(std::mem_fn(pmf)(std::forward(args)…))
{
返回std::mem_fn(pmf)(std::forward(args)…);
}
};
//如果你真的想用宏
#定义my_mem_fn(pmf)my_mem_fn_t()
然后:

auto get\u size=my\u mem\u fn\t;
//或者:my_mem_fn(&string::size);
字符串s(“你好”);

cout“std::map采用比较器的类型,而不是比较器对象。“Wat”和
mem\u fn
返回的东西根据定义不是无状态的。@T.C.我应该说“
std::map
可以采用比较器的类型并尝试默认构造它。”@T.C.为什么它不是无状态的?我认为可以使用纯无状态函子
struct
来实现它。我可能错了。你为什么不试着写呢?@ziz看看C++17版本,它几乎没有那么邪恶。嗯,C++17版本看起来更合理。任何类型都可以绑定到
自动F
?它是否与当前的非类型模板参数具有相同的约束?@ziz它有点像
template
,但只是
template
。如果它有更多的怪癖,我不知道,我还没有用过它你知道有没有一个编译器能够真正编译这个吗?我用
-std=c++1z
尝试了gcc 6.1.0,但gcc无法识别语法。@ziz-nope。请参阅,以获取(已接受的功能完整草案)建议I基于的C++17版本。
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>()
auto get_size = my_mem_fn_t<decltype(&string::size), &string::size>;
//          or: my_mem_fn(&string::size);

string s("hello");
cout << decltype(get_size)()(s) << '\n';  // prints 5