gpt4 book ai didi

c++ - 可组合的 monadic lambda/std::function with std::optional

转载 作者:行者123 更新时间:2023-12-01 14:29:10 36 4
gpt4 key购买 nike

我正在尝试构建一个 Filter可以作为可组合错误处理调用的类型(即带有 << 实现 >>= 的 Maybe monad)(理想情况下)与(至少)lambda 和 std::function 一起工作在 C++17 中(不需要与旧标准兼容)。理想情况下,应该像这样工作:

// two example Filter's instantiated from lambda's
Filter g = [](const int a, const int b) -> float {
return a + b;
};
Filter f = [](const float c) -> std::optional<int> {
if c < 0 return std::nullopt;
else return c + 1;
};

// compose them - only two right now for brevity
auto h = f << g; // so that this implements f(g(...))

// and then later call them with some arguments
h(1.0, 2.0);

如果任何中间函数返回std::nullopt , 我需要整个组合返回 std::nullopt并为此可以处理任意数量的组合函数(可能返回也可能不返回可选值)。

我目前的实现(受 this post 启发)适用于 std::function当组合两个简单的函数时,但当组合多个改变返回类型是否可选的函数时经常失败,因为类型推导非常脆弱。

#include <functional>
#include <optional>
#include <type_traits>

template <typename TReturn, typename... TArgs>
class Filter {

public:

/**
* The filter function that we evaluate.
*/
std::function<TReturn(TArgs...)> eval_;

/**
* Construct a filter from a std::function.
*/
Filter(std::function<TReturn(TArgs...)> f) : eval_(f) {}

/**
* Apply the filter to given arguments.
*/
auto operator()(TArgs... args) const {
return this->eval_(args...);
}

/**
* Compose this function, `f`, and `g`.
*/
template <typename TOReturn, typename... TOArgs>
auto operator<<(Filter<TOReturn, TOArgs...> other) const -> Filter<TReturn, std::optional<TOArgs>...> {

// the result of the resulting function f(g(...))
using TFReturn = std::optional<typename TReturn::value_type>;

// the type of the resulting function f(g(...))
using TFuncType = std::function<TFReturn(std::optional<TOArgs>...)>;

// construct (and return) the composed function
TFuncType f = [this, other](std::optional<TOArgs>... args) -> TFReturn {

// if we got a good value, perform the function composition
if ((args && ...)) {

// evaluate g over the input arguments
auto gresult = other(*(args)...);

// if we got a non-fail result from g, then call f
if (gresult) {

// and evaluate our own function over the result
return this->eval_(gresult);

}

} // END: if ((args && ...))

// if anything falls through, return failur
return std::nullopt;

};

return f;

} // END: operator<<


}; // END: class Filter


auto main() -> int {

// a couple of test functions
std::function<int(float, float)> f1 = [](const float a, const float b) -> int {
return a * b;
};

std::function<std::optional<int>(int)> f2 = [](const int c) -> std::optional<int> {
if (c < 0) return std::nullopt;
else return c;
};

std::function<std::optional<int>(int)> f3 = [](const int d) -> std::optional<int> {
if (d > 10) return 10;
else return d;
};

// these construct fine if I have explicitly typed std::function's above.
Filter f = f3;
Filter g = f2;
Filter h = f1;

// build the composition
auto F = g << h; // this works!
// auto F = f << g << h; // this does not work

// evaluate our composition over different arguments
auto x = F(1.0, 2.0);
auto y = F(-1.0, 2.0);

}


组合两个简单函数,f << g , 有效但 f << g << h当前失败并出现以下错误:

filter.cpp: In instantiation of ‘Filter<TReturn, std::optional<TOArgs>...> Filter<TReturn, TArgs>::operator<<(Filter<TOReturn, TOArgs ...>) const [with TOReturn = std::optional<int>; TOArgs = {int}; TReturn = std::optional<int>; TArgs = {int}]’:
filter.cpp:98:17: required from here
filter.cpp:55:43: error: no match for call to ‘(const std::function<std::optional<int>(int)>) (std::optional<int>&)’ 55 | return this->eval_(gresult); | ~~~~~~~~~~~^~~~~~~~~
In file included from /usr/include/c++/10/functional:59, from filter.cpp:1:
/usr/include/c++/10/bits/std_function.h:617:5: note: candidate: ‘_Res std::function<_Res(_ArgTypes ...)>::operator()(_ArgTypes ...) const [with _Res = std::optional<int>; _ArgTypes = {int}]’ 617 | function<_Res(_ArgTypes...)>:: | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~
/usr/include/c++/10/bits/std_function.h:618:25: note: no known conversion for argument 1 from ‘std::optional<int>’ to ‘int’ 618 | operator()(_ArgTypes... __args) const | ~~~~~~~~~^~~~~~~~~~
/usr/include/c++/10/bits/std_function.h:601:7: error: ‘std::function<_Res(_ArgTypes ...)>::function(_Functor) [with _Functor = Filter<TReturn, TArgs>::operator<< <std::optional<int>, {int}>::<lambda(std::optional<int>)>; <template-parameter-2-2> = void; <template-parameter-2-3> = void; _Res = std::optional<int>; _ArgTypes = {std::optional<int>}]’, declared using local type ‘Filter<TReturn, TArgs>::operator<< <std::optional<int>, {int}>::<lambda(std::optional<int>)>’, is used but never defined [-fpermissive] 601 | function<_Res(_ArgTypes...)>::

如何修改类型推导以支持 std::optional<T>(...)T(...)在任意组合中发挥作用?或者是否有一种根本不同的方法来处理此解决方案?

最佳答案

不确定是否理解您的代码,但是...在我看来问题出在本节中(删除注释并稍微简化)

auto gresult = other(*(args)...);

if (gresult)
return this->eval_(gresult);

什么类型是gresult

我想你期望那是一个 std::optional某种类型,因此您测试是否有效( if (gresult) )并将其传递给以下 eval_() .

但是结合 g() 会发生什么?和 h() ?并结合f()

如果我没理解错的话,h()之前执行并返回 int ;所以gresultint .

当你检查

if (gresult)

你不检查 gresult是有效的,但如果 gresult是否为零。

但这有效(我的意思是...编译)并且整数值用于调用 g()等待 int const .

但是当 g() 的结果

auto gresult = other(*(args)...);

(即 std::optional<int> )用于调用 f() (等待 int ),你有那个

if (gresult)

正确检查是否gresult是有效的,但是当您调用 f()

   return this->eval_(gresult);

你传递给f()一个std::optional<int>() , 不是 int .

不确定解决方案(不确定您到底想要什么以及 std::option 推导指南)但在我看来您应该强加 gresultstd::option某种类型的

std::option  gresult{ other( args.value()... ) };

所以下面检查

if ( gresult )

gresult 的有效性有关, 接下来你必须传递 gresult到以下功能

return this->eval_( gresult.value() );

请注意,在以下代码中,

int a;

std::optional b{a};
std::optional c{b};

static_assert( std::is_same_v<decltype(b), std::optional<int>> );
static_assert( std::is_same_v<decltype(c), std::optional<int>> );

两者都是bcstd::optional<int>

我的意思是...使用推导指南 std::optional , 如果参数是 std::optional ,结果类型相同。

我想这应该对你有用,但我不确定你到底想要什么。

关于c++ - 可组合的 monadic lambda/std::function with std::optional,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62903225/

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