C++ 放宽枚举类和布尔模板参数的constexpr要求
考虑代码,其中有一个函数C++ 放宽枚举类和布尔模板参数的constexpr要求,c++,templates,C++,Templates,考虑代码,其中有一个函数累加,它执行繁重的调度程序函数过程。累积函数在热循环中测试参数,因此该参数是模板化的 enum类Op{ 乘 添加 }; 样板 整数累加(常数std::vector和vec){ INTA=op==op::乘法?1:0; 用于(INTV:vec) 如果constexpr(op==op::Add)a+=v;否则a*=v; 返回a; } int进程(const std::vector&vec,Op){ 收益累加(vec); } 您可能已经注意到,由于从进程传递的模板参数不是co
累加
,它执行繁重的调度程序函数过程
。累积函数在热循环中测试参数,因此该参数是模板化的
enum类Op{
乘
添加
};
样板
整数累加(常数std::vector和vec){
INTA=op==op::乘法?1:0;
用于(INTV:vec)
如果constexpr(op==op::Add)a+=v;否则a*=v;
返回a;
}
int进程(const std::vector&vec,Op){
收益累加(vec);
}
您可能已经注意到,由于从进程传递的模板参数不是constexpr,所以此代码不会编译。但是,当模板参数是bool,尤其是enum类时,没有理由不编译它
这样的代码在实践中经常出现,当一个执行繁重工作的函数有几个变体时(我们只想在代码库中保留一个副本)。是否有建议或讨论使此类代码在未来有效
(C++有太多的特性,尽管我需要的一个特性缺失了:p)
但是,当模板参数是bool,尤其是enum类时,没有理由不编译它
当参数是值很少的bool
或enum
时,没有任何东西禁止您选择带有if
或开关的情况
int process1 (const std::vector<int> &vec, bool b) {
if ( b == true )
return accumulate<true>(vec);
else
return accumulate<false>(vec);
}
int process2 (const std::vector<int> &vec, Op op) {
switch ( op ) {
case Op::Multiply:
return accumulate<Op::Multiply>(vec);
break;
case Op::Add:
return accumulate<Op::Add>(vec);
break;
// other cases
// default
}
}
int process1(const std::vector&vec,bool b){
如果(b==true)
收益累加(vec);
其他的
收益累加(vec);
}
int process2(const std::vector&vec,Op){
开关(op){
案例Op::乘法:
收益累加(vec);
打破
案例Op::添加:
收益累加(vec);
打破
//其他情况
//违约
}
}
但是,当模板参数是bool,尤其是枚举类时,没有理由不进行编译。
有,op
不是编译时间常数。类型一点也不重要。@tkausl当它是枚举类或布尔时,编译器1)知道所有的可能性。2) 它们只有很少。这就足够编译代码了。对于允许枚举的问题,有一个建议是,您可以生成枚举中不存在的枚举值。即使对于枚举类也是如此。查看std::byte
。您可以执行std::byte foo{42}
,即使std::byte
没有枚举。谢谢!这就是代码库当前的样子。我认为这是一种非常常见的情况,尤其是在api服务的上下文中:传入的请求中有各种参数,为了加快实现速度,我们对实现进行了模板化。如果这个开关调度可以卸载到编译器中,那就太好了。开关块是乏味的,也是许多小错误的根源。再添加一种请求,在开关块中添加一个新条目,但是你忘记了break语句,glhf@boinkboink-对于当前语言,我知道的唯一替代方法是将op
值嵌入std::integral_常量
;因此,该值可以作为函数的参数传递,不同的op
值将成为不同的类型。@boinkboink:可能会出现缺少中断、缺少开关大小写的警告。但即使使用std::integral\u常量
,也应该完成从运行时值到编译时值的转换/分派。@Jarod42-Oh,是:我在考虑使用std::integral_constant
以防op
值是process()的调用方已知的编译时(模板参数或constepr
值)。