【发布时间】:2019-06-05 20:22:34
【问题描述】:
这是一个 Result 类的定义,旨在模拟 Haskell 中的 Either monad 的逻辑(Left 是 Failure;Right 是 Success)。
#include <string>
#include <functional>
#include <iostream>
template <typename S, typename F>
class result
{
private:
S succ;
F fail;
bool pick;
public:
/// Chain results of two computations.
template <typename T>
result<T,F> operator&&(result<T,F> _res) {
if (pick == true) {
return _res;
} else {
return failure(fail);
}
}
/// Chain two computations.
template <typename T>
result<T,F> operator>>=(std::function<result<T,F>(S)> func) {
if (pick == true) {
return func(succ);
} else {
return failure(fail);
}
}
/// Create a result that represents success.
static result success(S _succ) {
result res;
res.succ = _succ;
res.pick = true;
return res;
}
/// Create a result that represents failure.
static result failure(F _fail) {
result res;
res.fail = _fail;
res.pick = false;
return res;
}
};
当尝试使用 && 运算符组合两个结果时,一切正常:
int
main(int argc, char* argv[])
{
// Works!
auto res1 = result<int, std::string>::success(2);
auto res2 = result<int, std::string>::success(3);
auto res3 = res1 && res2;
}
但是当尝试在结果之上链接计算时,会出现编译错误:
result<int, std::string>
triple(int val)
{
if (val < 100) {
return result<int, std::string>::success(val * 3);
} else {
return result<int, std::string>::failure("can't go over 100!");
}
}
int
main(int argc, char* argv[])
{
// Does not compile!
auto res4 = result<int, std::string>::success(2);
auto res5a = res4 >>= triple;
auto res5b = res4 >>= triple >>= triple;
}
来自clang++的错误如下:
minimal.cpp:82:21: error: no viable overloaded '>>='
auto res5a = res4 >>= triple;
~~~~ ^ ~~~~~~
minimal.cpp:26:17: note: candidate template ignored: could not match
'function<result<type-parameter-0-0, std::__1::basic_string<char,
std::__1::char_traits<char>, std::__1::allocator<char> > > (int)>' against
'result<int, std::__1::basic_string<char, std::__1::char_traits<char>,
std::__1::allocator<char> > > (*)(int)'
result<T,F> operator>>=(std::function<result<T,F>(S)> func) {
^
minimal.cpp:83:32: error: invalid operands to binary expression ('result<int,
std::string> (int)' and 'result<int, std::string> (*)(int)')
auto res5b = res4 >>= triple >>= triple;
知道如何解决这个问题吗?
【问题讨论】:
-
在我看来,
triple是一个函数。您是否尝试过调用它,就像使用result::success一样?投票结束是一个错字。 -
@AlgirdasPreidžius 这个想法是将函数作为参数提供给
>>=运算符。有什么错别字? -
在以前已知的_463035818 的答案之上,如果没有两个函数指针的附加运算符或
res4 >>= triple周围的显式括号,auto res5b = res4 >>= triple >>= triple;将无法工作,因为operator >>=是从右到左的。它将首先尝试在triple和triple上应用>>=。 -
我写了一篇详细的帖子,解释了如何干净高效地实现
Result,使其成为 sum 类型。它解决了您的问题,并且避免使用std::function,以便编译器可以内联所有内容。语法最终更接近 Haskell 的
标签: c++ templates operator-overloading either