Switch语句和整数模板值

3

我知道如果我实例化一个模板,例如:

template<int i>
int ReturnMeDouble()
{
    return 2 * i;
}

那么编译器需要在编译时评估i的值。我的问题(为简单起见)是,我希望我的程序根据变量调用两个函数中的一个。我的代码大致如下:

int returnValue = 0;
switch(value)
{
    case 1:
    case 2:
    case 3:
    case 4:
        returnValue = ReturnMeDouble<value>();
        break;
    case 5:
    case 6:
        returnValue = ReturnMeTriple<value>();
        break;
}

真正的ReturnMe...函数做的事情要复杂一些。显然,我可以使用switch语句并在每个case语句下提供单独的调用,但是我想知道是否有什么我错过的东西,因为对我来说似乎很明显(如果编译器不这样认为),在第一种情况下,ReturnMeDouble只能使用四个值之一进行调用。
是不是简单地说,编译器需要在需要实例化的四个单独函数模板周围放置条件流(有效地避免手动执行的操作),而它不知道如何执行?
有没有更优雅的方法呢?
编辑:为了澄清-较不平凡的实现使用整数值对函数内的类型选择应用一些元程序。

根据你对“优雅”的理解,你可能想看看boost.pp,但是没有办法将运行时的值带回到编译时的领域。 - PlasmaHH
1
函数指针就会在我的脑海中浮现……如果可能值的范围很小(如果范围很大,您可能要避免使用模板,因为它们会导致代码膨胀),则可以使用函数指针数组。 - dyp
我认为问题关键在于returnValue是否在编译时可知。我猜测它是不可知的。 - stardust
有必要将“ReturnMe…”函数模板化吗?难道你不能只将一个值作为参数传递给它们吗? - borisbn
实际上,ReturnMe...正在对二进制流进行一些操作,提取不同大小的值,然后将它们强制转换回整数。这样做最终会变成大约10行代码,没有复杂的控制流程,因此我试图在调用者或被调用者中使用它来替代几个if语句。 - Fritz
2个回答

2

我认为你已经在尝试解释中准确地表述了。

标准的解释是,你提供的模板参数必须是编译时已知的常量。由于你提供的值是一个直到运行时才知道的变量,所以不允许这样做。

是的,在这种特定情况下,具有良好优化器的编译器可以推导出需要提供的四个常量值。

然而还有很多其他情况可能会更加复杂。例如,编译器可以结合某些特定的优化来推导出一个特定值实际上是编译时常量,但是另一个缺乏该特定优化的编译器则无法知道。

面对一个他们无法回答的问题(“编译器能否在编译时推导出这个值?”),委员会采取了相当保守的态度,并指定了一个相对狭窄的可接受输入范围。当然,编译器可以选择接受其他表达式作为扩展。

从委员会的角度来看,我认为添加constexpr是一种尝试,旨在实现至少相似的东西 - 允许更大范围的计算以一种让编译器知道结果应该作为编译时常量可用的方式进行。考虑到即使是这样实现的复杂性,我猜测在像你上面给出的情况下强制进行编译时计算是不太可能的(至少在不久的将来)。


正如我所担心的那样 - 没关系。解决方案可能不太优雅,但在我编写下一个函数时,我可能会为标准委员会施加的限制感到高兴。 - Fritz

1

由于您没有告诉我们函数模板参数的“不太琐碎”的用法,因此我要说解决这个问题的方法是将函数的模板化去掉,只传递运行时参数。

然后您就不必在任何地方进行运行时到编译时值的转换,该值只会在所有情况下在运行时传递。

换句话说:int ReturnMeDouble(int i) { ... }


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