8

是否可以从模板函数参数中推断出非类型模板参数?

考虑这个简单的模板:

template <int N> constexpr int factorial()
{
        return N * factorial<N - 1>();
}

template <> constexpr int factorial<0>()
{
        return 1;
}

template <> constexpr int factorial<1>()
{
        return 1;
}

我希望能够进行更改factorial,以便我可以这样称呼它:

factorial(5);

并让编译器在编译时计算出 N 的值。这可能吗?也许加上一些花哨的 C++11?

4

7 回答 7

9

我相信您当前的代码通常如下编写:

constexpr factorial (int n)
{
    return n > 0 ? n * factorial( n - 1 ) : 1;
}

如果你用一个常量表达式来调用它,比如factorial(5),那么所有的编译器魔法都会发挥作用。但是如果你这样做int a = 3; factorial(a)了,那么我认为它会依赖于一个传统的函数——即它不会建立一个预先计算的答案的查找表。

一般来说,你应该尽可能地标记每个函数和构造函数constexpr。您什么都不会丢失,编译器会在必要时将其视为普通函数。

于 2012-01-12T15:09:54.207 回答
7

不可能,除非你有时光机。

函数的参数在运行时处理。是的,在您的情况下,它是一个字面常量,但这是一种特殊情况。

在函数定义中,参数类型在编译时是固定的(因此,可以用来推导模板参数),但参数仅在运行时固定。

你为什么需要这个?是否只是为了不必键入<>'s?

于 2012-01-12T15:01:46.070 回答
1

我不认为你能做到这一点;您可以这样做的唯一方法是拥有一个constexpr函数参数,然后将其作为template模板版本的参数传递factorial,但constexpr不允许使用函数参数。

于 2012-01-12T15:01:27.997 回答
1

不,你不能那样做。模板参数只能从函数参数的类型推导出来,而不是value,这通常在编译时是不知道的。

当然,你可以重写factorial为非模板constexpr函数;如果参数是已知的,那么它将在编译时进行评估。

于 2012-01-12T15:02:43.930 回答
0

不,这是不可能的,除非你想创建一个巨大的 switch 语句:

int getFactorial( const int v )
{
  switch ( v )
  {
    case 1 : return factorial<1>();
    case 2 : return factorial<2>();
    //etc
    default:
       ;
  }
  return 0;
}
于 2012-01-12T15:01:47.830 回答
0

使用邪恶的宏:

#define factorial(X) factorial<X>()
于 2016-05-25T00:47:10.887 回答
0

此类问题的一种可能的解决方法是使用struct以下方法:

template <int X>
struct constant {
    operator int () { return X; }
};

然后我们可以constant<X>像这样重载:

template <int X>
void f (constant<X>)

利用X编译时和运行时重载的值f (int)。烦人的部分是它需要在调用站点上进行一些纪律,因为每个文字常量都必须包装为constant<X> {}(使用宏或类似的东西)。

于 2020-01-16T07:48:50.310 回答