C++能像ML的case表达式一样实现吗?

3
所以,在C++中我遇到过这种情况几次,我真的想写出类似于以下的代码:
case (a,b,c,d) of
     (true, true, _, _ )     => expr
   | (false, true, _, false) => expr
   | ...

但在 C++ 中,我总是会得到类似这样的结果:

bool c11 = color1.count(e.first)>0;
bool c21 = color2.count(e.first)>0;
bool c12 = color1.count(e.second)>0;
bool c22 = color2.count(e.second)>0;
// no vertex in this edge is colored
// requeue
if( !(c11||c21||c12||c22) )
{
    edges.push(e);
}
// endpoints already same color
// failure condition
else if( (c11&&c12)||(c21&&c22) )
{
    results.push_back("NOT BICOLORABLE.");
    return true;
}
// nothing to do: nodes are already
// colored and different from one another
else if( (c11&&c22)||(c21&&c12) )
{
}
// first is c1, second is not set
else if( c11 && !(c12||c22) )
{
    color2.insert( e.second );
}
// first is c2, second is not set
else if( c21 && !(c12||c22) )
{
    color1.insert( e.second );
}
// first is not set, second is c1
else if( !(c11||c21) && c12 )
{
    color2.insert( e.first );
}
// first is not set, second is c2
else if( !(c11||c21) && c22 )
{
    color1.insert( e.first );
}
else
{
    std::cout << "Something went wrong.\n";
}

我想知道是否有办法简化所有的if和else,因为它们看起来容易出错。如果能像SML一样,在C++中表达式(或语句)不是穷尽时让编译器发出警告,那就更好了。我知道这个问题有点含糊不清。总的来说,如何用简洁的方式在C++中表示具有任意数量变量的穷尽真值表呢?谢谢。

3个回答

7

我喜欢Alan的解决方案,但我不同意他的结论,即它过于复杂。如果你有C++11访问权限,它几乎提供了你所需的所有工具。你只需要编写一个类和两个函数:

namespace always {

struct always_eq_t {
};

template <class lhs_t>
bool operator==(lhs_t const&, always_eq_t)
{
    return true;
}

template <class rhs_t>
bool operator==(always_eq_t, rhs_t const&)
{
    return true;
}

}  // always

然后您可以以与ML相对类似的方式编写函数:

#include <tuple>
#include <iostream>

void f(bool a, bool b, bool c, bool d)
{
    always::always_eq_t _;

    auto abcd = std::make_tuple(a, b, c, d);

    if (abcd        == std::make_tuple(true,  true, _, _)) {
        std::cout << "true, true, _, _\n";
    } else if (abcd == std::make_tuple(false, true, _, false)) {
        std::cout << "false, true, _, false\n";
    } else {
        std::cout << "else\n";
    }
}

int
main()
{
    f(true, true, true, true);
    f(false, true, true, false);

    return 0;
}

在C++中,你经常会考虑是否有一种合理的类型可以创建,以帮助更轻松地编写代码?此外,如果你有机器学习背景,研究C++模板将受益匪浅。它们非常有助于在C++中应用函数式编程风格。


5

C++传统上面向个人,无论语法如何,你都不能做出以下类似的操作。

if ([a,b,c,d] == [true,true,false, false]) {}

新的C++标准允许您内联定义常量数组,因此可以定义一个类作为构造函数接受一个数组并支持这样的比较。大致如下:
auto x = multi_val({a,b,c,d});
if (x == multi_val({true, true, false, false}))
{ ... }
else if (x == multi_val(etc.))

但是现在要进行类似 _ 的部分匹配,这并不直接支持,你必须使你的类变得更加复杂以应对这种情况,例如使用 maybe 模板类型来处理

multi_val(true, true, maybe<bool>(), maybe<bool>)

这涉及到相当深奥的C++领域,对于如此基础的东西来说绝对不是我所做的。


2
对于C++11,假设您只想匹配固定数量的布尔值并且可以在没有_模式匹配的情况下生存,则使用 [1](展开所需的变量数)。

我仍在使用模板解决方案来匹配使用lambda或functor表示的任意类型。

-编辑-

如承诺的那样,[2] 匹配任意类型,包括未指定的值。

请注意一些警告:

  1. 此代码仅适用于4个变量(实际上是我第一次涉足模板元编程)。这可以通过可变模板得到很大改善。
  2. 它可以工作,但不是非常整洁或组织良好。更多是概念验证,需要在引入到生产代码之前进行清理。
  3. 我对match函数不满意。我希望使用初始化列表将要评估的表达式传递给它,并在第一次匹配时停止(使用当前实现,每个匹配条件都将被执行),但是我无法迅速考虑如何通过单个初始化列表传递不同类型的表达式匹配对象。

我无法想出任何方法来验证真值表是否详尽。

谢谢,

-nick

[1]

constexpr int match(bool v, int c)
{
    return v ? (1 << c) : 0;
}
constexpr int match(bool a, bool b)
{
    return match(a, 0) | match(b, 1);
}

int main()
{
    int a = true;
    int b = false;

    switch(match(a, b))
    {
        case match(false, false):
            break;
        case match(false, true):
            break;
        case match(true, false):
            break;
        case match(true, true):
            break;
    }

}

[2]

template<typename V1, typename V2, typename V3, typename V4>
class pattern_match_t
{
private:
    V1 value_0;
    V2 value_1;
    V3 value_2;
    V4 value_3;
public:
    typedef std::function<void(V1, V2, V3, V4)> expr_fn;

    template <typename C1, typename C2, typename C3, typename C4>
    pattern_match_t<V1, V2, V3, V4>& match(C1 a, C2 b, C3 c, C4 d, expr_fn fn)
    {
        if(value_0 == a && value_1 == b && value_2 == c && value_3 == d)
            fn(value_0, value_1, value_2, value_3);
        return *this;
    }

    pattern_match_t(V1 a, V2 b, V3 c, V4 d)
     : value_0(a), value_1(b), value_2(c), value_3(d)
    {
    }
};

template<typename T>
class unspecified
{};

template<typename T>
constexpr bool operator==(unspecified<T>, const T&)
{
    return true;
}

template<typename T>
constexpr bool operator==(const T&, unspecified<T>)
{
    return true;
}

template<typename V1, typename V2, typename V3, typename V4>
pattern_match_t<V1, V2, V3, V4> pattern_match(V1 a, V2 b, V3 c, V4 d)
{
    return pattern_match_t<V1, V2, V3, V4>(a, b, c, d);
}

int main()
{

    bool test_a = true;
    std::string test_b = "some value";
    bool test_c = false;
    bool test_d = true;

    pattern_match(test_a, test_b, test_c, test_d)
        .match(true, unspecified<std::string>(), false, true, [](bool, std::string, bool, bool)
        {
            return;
        })
        .match(true, "some value", false, true, [](bool, std::string, bool, bool)
        {
            return;
        });
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接