gpt4 book ai didi

c++ - 是否可以允许一种 std::function 类型接受具有不同签名的 lambda

转载 作者:IT老高 更新时间:2023-10-28 21:40:51 28 4
gpt4 key购买 nike

我有一个高阶函数 map类似于 STL for_each , 并映射一个 std::function vector 上的对象的东西。

template<class T, class U>
vector<U> map(function<U (T)> f, vector<T> xs) {
vector<U> ret;
for (auto &x: xs)
ret.push_back(f(x));
return ret;
}

现在,我想让这个高阶函数同时获取 function<int (const vector<T>&)> 类型的两个对象和 function<int (vector<T>)> ,如随附的最小示例所示。

问题是function<int (const vector<T>&)>function<int (vector<T>)>似乎可以相互转换(见 headhead2 ),但 map不会采用 const 引用版本 function<int (const vector<int>&)> (见 Q1)。

可以告诉map接受带有显式转换的 const 引用版本( Q2 ),但这相当麻烦。

我想知道,一般来说,是否可以编写函数 dereffunction<int (const vector<T>&)> 中删除 const 引用并返回 function<int (vector<T>)> ?

(如果上面是可能的,那么我不必为 const refs 编写两个相同的 map 重载/实现)。

谢谢。

#include <vector>
#include <functional>
using namespace std;

template<class T, class U>
vector<U> map(function<U (T)> f, vector<T> xs) {
vector<U> ret;
for (auto &x: xs)
ret.push_back(f(x));
return ret;
}

int main() {
vector<vector<int>> m;
function<int (const vector<int>&)> head = [](const vector<int>& a) {return a[0];};
function<int (const vector<int>&)> head1 = [](vector<int> a) {return a[0];}; //conversion OK
function<int (vector<int>)> head2 = [](const vector<int>& a) {return a[0];}; //conversion OK
map(head2,m); //OK

map(head,m); //Q1: problem line, implicit conversion NOT OK
map(function<int (vector<int>)>(head),m); //Q2: explicit conversion OK
map(deref(head),m); //Q3: ??How-to, deref takes a std::function f and returns a function with const ref removed from its signature

return 0;
}

--- 编辑 ---

我对 deref 特别感兴趣like 函数或元函数,可以从 std::function 的类型签名中删除 const ref对象,这样我至少可以做Q2自动。

我知道,正如@Brian 和@Manu 正确指出的那样,使用 std::function指定类型不是常规的,但我想知道我上面问的是否可行。 个人,我认为代码为 std::function更清晰,考虑到泛型函数类型 Func<T1, T2, T3, ...,Tn, Tresult>在 C# 中使用。这是如果类型删除的成本是可以容忍的。

我完全同意 c++ 可以推断返回类型并在类型错误时给出错误消息。也许这只是一个口味问题,我更愿意在编写函数签名时把它拼出来。

最佳答案

我明白你为什么使用 std::function:你必须知道转换的返回类型才能创建 vector ,对吧?

但请考虑一种完全不同的方法。给定元函数 std::result_of 您可以计算函数调用的结果类型,因此只需编写:

template<typename F , typename CONTAINER , typename T = typename std::result_of<F(typename CONTAINER::value_type)>::type>
std::vector<T> map( F f , CONTAINER&& container )
{
std::vector<T> result;

for( auto& e : container )
result.emplace_back( f( e ) );

return result;
}

优点:

  • 不要滥用 std::function:永远想想 std::function 做了什么(即类型删除),不要'不要将其用作通用函数类型。

  • 依赖鸭子类型而不是耦合类型:别担心,如果出现问题,它也不会编译。

  • 适用于任何标准库容器,因为我们使用 value_type 特征提取元素类型,而不是使用 std::vector 直接。

  • 代码更加清晰和高效,这都是因为减少了 std::function 的使用。

关于问题“是否可以编写一个接受多个签名的 lambdas 的函数?

使用 std::function 您可以在几行代码中编写类似于 Boost.OverloadedFunction 的内容:

template<typename F , typename... Fs>
struct overloaded_function : public std_function<F> , public std_function<Fs>...
{
overloaded_function( F&& f , Fs&&... fs ) :
std_function<F>{ f },
std_function<Fs>{ fs }...
{}
};

其中 std_function 是一个元函数,它给定一个函数类型 F 返回带有 F 签名的 std::function 实例。我把它留给读者作为游戏/挑战。

仅此而已。使用类似 make 的功能对其进行改进:

template<typename F , typename... Fs>
overloaded_function<F,Fs...> make_overloaded_function( F&& f , Fs&&... fs )
{
return { std::forward<F>( f ) , std::forward<Fs>( fs )... };
}

你准备好了:

auto f = make_overloaded_function( [](){ return 1; } ,
[](int,int){ return 2; } ,
[](const char*){ return 3; } );

f(); //Returns 1
f(1,2); //Returns 2
f("hello"); //Returns 3

编辑:“谢谢。但是,我真正想要的是一个元函数,它接受可调用的签名,并从签名中删除 const refs。

好的,让我试试:std::decay 元函数在将参数按值传递给给定类型时应用衰减完成。这包括删除 cv 限定符、删除引用等。因此,像您这样的元函数可能是采用函数签名类型并将衰减应用于其所有参数的东西:

template<typename F>
struct function_decay;

template<typename R typename... ARGS>
struct function_decay<R(ARGS...)>
{
using type = R(typename std::decay<ARGS>::type...);
};

这应该可以完成工作。

我写这个是因为你在评论中明确要求它,但我强烈建议你使用我最初向你展示的替代方案,因为它与你的方式相比有很多优势。
也就是说,我希望这个答案有助于解决您的问题。

关于c++ - 是否可以允许一种 std::function 类型接受具有不同签名的 lambda,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24561846/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com