在像Haskell这样的功能导向语言中,可以将函数定义重载为参数签名的几个轴。 C ++支持参数的数量和类型。其他语言支持参数值甚至保护子句(测试条件参数的代码。)例如Haskell中的阶乘实现:
factorial :: (Integral a) => a -> a
factorial 0 = 1
factorial n = n * factorial (n - 1)
当参数为0时,factorial的定义与参数为任何其他整数时的factorial定义不同。
我还没有在C ++中找到这种功能,并且首先想到用语言实现它很难。进一步的反思使我觉得它实际上相当容易,并且是语言的一个很好的补充,所以我必须错过它。
有没有办法在本机语法或模板中执行此操作?
答案 0 :(得分:2)
有这样的事情,它被称为模板专业化。基本上,除了通用模板定义之外,您还可以为给定类型定义模板。你可以阅读它here
template<std::size_t N>
struct factorial {
static constexpr unsigned long long value = N * factorial<N - 1>::value;
};
template<>
struct factorial<0> {
static constexpr unsigned long long value = 1;
}
auto foo = factorial<10>::value;
阶乘模板&#34;功能&#34;也使用模板特化,但由于模板的性质,它只能计算编译时间值(模板元编程):
{{1}}
据我所知,在给定函数中运行时没有这样的东西(除了switch / if branches)。
答案 1 :(得分:2)
我认为这里真正的答案是没有确切的等价物。然而。模板特化很接近,但只能在编译时工作,有些限制了它的可用性。我们当然有分支,但与其他函数式编程语言中的模式匹配相比,功能有限。
目前有一个关于C ++模式匹配的提案:P0095r1,它允许以下阶乘定义,假设概念:
template <Integral I>
I factorial(I n) {
return inspect(n) {
0 => 1
n => n * factorial(n-1)
};
}
我对语法不完全确定,但话说回来,它只是一个提案,所以语法本身可能会改变。
答案 2 :(得分:1)
如果值在编译时已知,则可以使用模板
完成//recursively calls itself until N is 1
template<int N>
struct factorial<N>{enum{value = N * factorial<N-1>::value};};
//at which point, this will be called (stopping the recursion)
template<>
struct factorial<1>{enum{value = 1};};
如果值仅在运行时已知,则必须在运行时决定
int factorial_recursion(int n){
if(n == 1)
return 1;
else
return n * factorial_recursion(n - 1);
}
//or
int factorial_loop(int n){
int answer = 1;
for(int count = n; count > 1; --count)
answer *= count;
return answer;
}
答案 3 :(得分:0)
简短回答:没有C ++没有Haskell风格的模式匹配。另外值得一提的是,在Haskell示例中,您只有一个函数,而不是其中的两个函数,但您只需要一个更好的语法来检查输入值。在重载时,实际上有两个或多个具有相同名称但不同数量或类型的参数的函数。
更长/更真实的答案:通过template-metaprogramming可以提出类似于你所建议的内容。由于C ++模板允许值作为模板参数,而不仅仅是类型,因此您实际上可以构建这样的函数。模板语言显然是Turing完成的,因此您可以实际计算可用它计算的所有内容。 当然,它看起来很糟糕,导致大量的编译时间和难以理解初始写入后的代码。
答案 4 :(得分:0)
运行时分支是使用if
或三元运算符完成的
<condition> ? <if-true> : <if-false>
。
函数的重载在编译时完成,因此这意味着如果要根据值选择函数的重载,则必须在编译时严格知道该值。
以下是使用sfinae进行编译时分支的示例:
template<int n, std::enable_if_t<(n > 1), short> = 0>
constexpr int factorial(std::integral_constant<int, n>) {
return n * factorial(std::integral_constant<n - 1>{});
}
template<int n, std::enable_if_t<(n == 0), short> = 0>
constexpr int factorial(std::integral_constant<int, n>) { return 1; }
请注意enable_if_t
中使用的条件。如果不满足条件,它将使函数无效,并强制编译器尝试替代函数。
当然,语法不是很好。最好的方法是在运行时和编译时都有一个实现,但为此你必须使用传统的分支:
constexpr factorial(int n) {
return n == 0 ? 1 : n * factorial(n - 1);
}
答案 5 :(得分:0)
int factorial(int n)
{
switch(n)
{
case 0: return 1;
default: return n * factorial(n - 1);
}
}