所以,我在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";
}
我想知道是否有任何方法可以清除所有这些,如果有的话,或者其他的,因为它似乎特别容易出错。如果在案例表达式(或C ++中的语句)并非详尽无遗的情况下,可能会让编译器像SML那样抱怨,那就更好了。我意识到这个问题有点模糊。也许,总而言之,如何用简洁的C ++中的任意数量的变量代表一个详尽的真值表?提前谢谢。
答案 0 :(得分:7)
我喜欢艾伦的解决方案,但我恭敬地不同意他的结论,即它过于复杂。如果您可以访问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 ++中,您经常要考虑是否有一种合理的类型可以帮助我更轻松地编写代码?另外,我认为如果你有ML背景,你将从检查C ++模板中受益匪浅。它们非常有助于在C ++中应用函数式编程风格。
答案 1 :(得分:5)
C ++传统上面向个人,无论语法如何,你都不可能做任何类似的事情。
if ([a,b,c,d] == [true,true,false, false]) {}
New C ++标准有一些东西可以让你定义内联常量数组,因此可以定义一个类,它将数组作为构造函数并支持这样的比较。像
这样的东西auto x = multi_val({a,b,c,d});
if (x == multi_val({true, true, false, false}))
{ ... }
else if (x == multi_val(etc.))
但现在要进行与_一样的部分匹配,这不是直接支持的,你必须让你的课程更加复杂以捏造它,比如使用一个可能的模板类型并且去
multi_val(true, true, maybe<bool>(), maybe<bool>)
这进入了相当令人兴奋的C ++领域,并且绝对不是我为那些如此基本的东西所做的事情。
答案 2 :(得分:2)
对于C ++ 11,假设您只想匹配固定数量的布尔值并且可以在没有_模式匹配的情况下生存[1](扩展为您需要的变量数)。
我还在研究一种替代解决方案,使用模板来匹配任意类型,使用lambdas或functor来表达。
- 编辑 -
正如所承诺的,[2]任意类型的模式匹配,包括。未指定的值。
请注意以下几点:
我想不出一种方法可以验证真值表是否详尽无遗。
干杯,
-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;
});
}