C++中能否在编译时评估一组constexpr函数?及实现问题
C++ constexpr模板函数检查多函数条件的编译错误解决
问题描述
刚接触C++模板,想要实现一个constexpr模板函数,接收一组返回值为bool、输入为int的函数作为参数包,检查给定值是否满足所有函数。提取核心代码后发现,Item 1的test函数使用is_in_v元函数时,因参数b不是常量表达式报错;但Item 2的test2函数传入相同值b却能正常编译运行。尝试过传递const引用,但未彻底解决问题,询问该需求是否可行及替代方案。
代码示例
constexpr bool f1 (int a) { return true; } constexpr bool f2 (int a) { return false; } constexpr bool f3 (int a) { return a > 3; } //Item 1 template<bool (*...func)(int)> constexpr bool test(int b) { return !is_in_v<bool, false, func(b)...>; } //Item 2 template<bool (*func)(int)> constexpr bool test2(int b) { return func(b); } int main () { static_assert(test<f1, f3>(5)); //ERROR: b is not a constant expression static_assert(test2<f3>(5)); //works fine }
原因分析
is_in_v是模板参数,要求所有传入的参数必须是编译期常量。Item 1中func(b)的b是函数形参,模板实例化阶段(编译期)b的值尚未确定,只有函数调用时才会传入,因此func(b)无法作为模板参数的常量表达式,导致报错。- Item 2的
test2仅将func(b)作为函数返回值,constexpr函数允许在编译期或运行期调用:当用static_assert调用时,传入的5是常量表达式,func(5)能在编译期完成计算,因此可以正常通过。
可行替代方案
你的需求完全可行,以下两种方案可以解决问题:
方案1:将输入值作为模板非类型参数
把b设为编译期常量,这样func(b)就能满足常量要求(更推荐用折叠表达式直接判断,逻辑更清晰):
constexpr bool f1(int a) { return true; } constexpr bool f2(int a) { return false; } constexpr bool f3(int a) { return a > 3; } template<int b, bool (*...func)(int)> constexpr bool test() { // 折叠表达式:所有func(b)为true才返回true,短路求值 return (... && func(b)); } int main() { static_assert(test<5, f1, f3>()); // 编译通过 // static_assert(test<2, f1, f3>()); // 断言失败,f3(2)返回false }
方案2:用折叠表达式替代is_in_v
保持b作为函数形参,在constexpr函数内部用折叠表达式计算,只要调用时传入的b是常量表达式,就能在编译期求值:
constexpr bool f1(int a) { return true; } constexpr bool f2(int a) { return false; } constexpr bool f3(int a) { return a > 3; } template<bool (*...func)(int)> constexpr bool test(int b) { // 折叠表达式:所有func(b)为true则返回true return (... && func(b)); } int main() { static_assert(test<f1, f3>(5)); // 编译通过,5是常量表达式 // static_assert(test<f1, f3>(2)); // 断言失败 int x = 5; test<f1, f3>(x); // 支持运行期调用,无需编译期结果时可用 }
补充说明
is_in_v本质是类型 traits 工具,依赖编译期常量参数,不适合用于这种需要在函数调用阶段计算的场景。而C++17引入的折叠表达式,能直接在constexpr函数内部对参数包进行逻辑运算,既满足编译期求值需求,又保留了函数形参的灵活性。
内容的提问来源于stack exchange,提问作者Vilim Hrupelj
相关产品推荐
相关产品推荐

