为什么没有std :: make_function()? [英] why is there no std::make_function()?

查看:99
本文介绍了为什么没有std :: make_function()?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

std :: function<> 是几乎任何可调用事物的有用的包装,包括自由函数,lambda,函数,成员函数, std :: bind 。然而,当创建一个 std :: function<> 时,必须明确指定函数签名为
(取自此处

std::function<> is a useful wrapper around almost any callable thing, including free functions, lambdas, functors, member functions, results from std::bind. However, when creating a std::function<>, one must explicitly specify the function signature as in (taken from here)

struct Foo {
    Foo(int num) : num_(num) {}
    void print_add(int i) const { std::cout << num_+i << '\n'; }
    int num_;
};

void print_num(int i)
{ std::cout << i << '\n'; }

struct PrintNum {
    void operator()(int i) const
    { std::cout << i << '\n'; }
};

// store a free function
std::function<void(int)> f_display = print_num;

// store a lambda
std::function<void()> f_display_42 = []() { print_num(42); };

// store the result of a call to std::bind
std::function<void()> f_display_31337 = std::bind(print_num, 31337);

// store a call to a member function
std::function<void(const Foo&, int)> f_add_display = &Foo::print_add;

// store a call to a member function and object
using std::placeholders::_1;
std::function<void(int)> f_add_display2= std::bind( &Foo::print_add, foo, _1 );

// store a call to a member function and object ptr
std::function<void(int)> f_add_display3= std::bind( &Foo::print_add, &foo, _1 );

// store a call to a function object
std::function<void(int)> f_display_obj = PrintNum();

,即使可以从分配的对象推断签名。看起来避免这种情况的一种自然方式(在模板化的代码中应该非常方便)是一个重载的函数模板 make_function (类似于 std :: make_pair std :: make_tuple ),上面的例子将简单地变成

even though the signature could be inferred from the assigned objects. It seems that a natural way to avoid this (which should be quite handy in heavily templated code) is an overloaded function template make_function (similar in spirit to std::make_pair or std::make_tuple), when above examples would simply become

// store a free function
auto f_display = make_function(print_num);

// store a lambda
auto f_display_42 = make_function([](){ print_num(42);});

// store the result of a call to std::bind
auto f_display_31337 = make_function(std::bind(print_num, 31337));

// store a call to a member function
auto f_add_display = make_function(&Foo::print_add);

// store a call to a member function and object
using std::placeholders::_1;
auto f_add_display2 = make_function(std::bind( &Foo::print_add, foo, _1));

// store a call to a member function and object ptr
auto f_add_display3 = make_function(std::bind( &Foo::print_add, &foo, _1));

// store a call to a function object
auto f_display_obj = make_function(PrintNum());

另一个可能的用例是获取任何类型的可调用对象的返回类型

Another possible use case is to get the return type for callable object of any kind

decltype(make_function(function_object))::return_type;

避免Piotr S.在这个问题

avoiding the traits magic in the answer by Piotr S. to this question.

所以,我的问题:为什么标准不提供这个功能?可以在没有编译器魔术的情况下实现 make_function ?还是需要编译器魔法? (即使那时第一个问题仍然存在。)

So, my question: why does the standard not provide this functionality? Can make_function be implemented without compiler magic? Or would it need compiler magic? (even then the first question remains.)

推荐答案

如这里和其他地方所说,有歧义问题可能会混淆类型引用。可能这些角落的情况下停止了一个 std :: make_function 被采纳,因为它不能够解决模糊,重载或工作与C ++自动类型转换。另一个反对它的论点,我看到很多是 std :: function 有开销(在类型擦除),很多人反对使用 std: :

As commented here and elsewhere, there is the ambiguity issue that can confuse type inferencing. Probably these corner cases stopped a std::make_function from being adopted as it would not be able to resolve ambiguity, overloading or work nicely with C++ automatic type conversions. Another argument against it that I see a lot is that std::function has overhead (in type erasure), and many people are against using std::function on that basis for anything other than storage of callables.

但是,对于不明确的情况,可以写一个 make_function 用于lambdas和其他可处理类型推断的可调用方法,避免在没有歧义时重复函数类型签名。一种方法(取自我的相关问题)如下:

However, for the non-ambiguous case, it is possible to write a make_function for lambdas and other callables that takes care of type inferencing, which avoids repeating function type signatures when there is really no ambiguity. One way to do it (taken from my related question) is as follows:

#include <functional>
#include <utility>
#include <iostream>
#include <functional>
using namespace std;

// For generic types that are functors, delegate to its 'operator()'
template <typename T>
struct function_traits
  : public function_traits<decltype(&T::operator())>
{};

// for pointers to member function
template <typename ClassType, typename ReturnType, typename... Args>
struct function_traits<ReturnType(ClassType::*)(Args...) const> {
  enum { arity = sizeof...(Args) };
  typedef function<ReturnType (Args...)> f_type;
};

// for pointers to member function
template <typename ClassType, typename ReturnType, typename... Args>
struct function_traits<ReturnType(ClassType::*)(Args...) > {
  enum { arity = sizeof...(Args) };
  typedef function<ReturnType (Args...)> f_type;
};

// for function pointers
template <typename ReturnType, typename... Args>
struct function_traits<ReturnType (*)(Args...)>  {
  enum { arity = sizeof...(Args) };
  typedef function<ReturnType (Args...)> f_type;
};

template <typename L> 
static typename function_traits<L>::f_type make_function(L l){
  return (typename function_traits<L>::f_type)(l);
}

//handles bind & multiple function call operator()'s
template<typename ReturnType, typename... Args, class T>
auto make_function(T&& t) 
  -> std::function<decltype(ReturnType(t(std::declval<Args>()...)))(Args...)> 
{return {std::forward<T>(t)};}

//handles explicit overloads
template<typename ReturnType, typename... Args>
auto make_function(ReturnType(*p)(Args...))
    -> std::function<ReturnType(Args...)> {
  return {p};
}

//handles explicit overloads
template<typename ReturnType, typename... Args, typename ClassType>
auto make_function(ReturnType(ClassType::*p)(Args...)) 
    -> std::function<ReturnType(Args...)> { 
  return {p};
}

// testing
using namespace std::placeholders;

int foo(int x, int y, int z) { return x + y + z;}
int foo1(int x, int y, int z) { return x + y + z;}
float foo1(int x, int y, float z) { return x + y + z;}

int main () {
  //unambuiguous
  auto f0 = make_function(foo);
  auto f1 = make_function([](int x, int y, int z) { return x + y + z;});
  cout << make_function([](int x, int y, int z) { return x + y + z;})(1,2,3) << endl;

  int first = 4;
  auto lambda_state = [=](int y, int z) { return first + y + z;}; //lambda with states
  cout << make_function(lambda_state)(1,2) << endl;

  //ambuiguous cases
  auto f2 = make_function<int,int,int,int>(std::bind(foo,_1,_2,_3)); //bind results has multiple operator() overloads
  cout << f2(1,2,3) << endl;
  auto f3 = make_function<int,int,int,int>(foo1);     //overload1
  auto f4 = make_function<float,int,int,float>(foo1); //overload2

  return 0;
}

这篇关于为什么没有std :: make_function()?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆