如何检测函数在参数非constexpr时仍能产生constexpr结果?
如何用Concept检测“未使用非constexpr参数仍能生成constexpr结果”的函数特性
有些constexpr函数存在这样的特性:即便传入的参数不是constexpr值,但只要该参数并未被实际使用,函数依然能生成constexpr结果。比如std::integral_constant::operator T:
#include <utility> std::integral_constant<int, 42> a; constexpr int b = a; // 编译通过!
现在需要编写一个Concept,用来测试类型是否具备这类特性——比如区分以下两个结构体:
- 结构体A的
operator bool()是constexpr,且返回值不依赖成员变量 - 结构体B的
operator bool()是constexpr,但返回值依赖成员变量
期望的测试逻辑是:
#include <utility> struct A {explicit constexpr operator bool() const {return true;}}; struct B {int x = 1; explicit constexpr operator bool() const {return x;}}; // 待实现的Concept C template <typename T> concept C = /* 正确约束 */; static_assert(C<A>); // 应通过断言 static_assert(!C<B>); // 应通过断言
但如果直接写如下Concept,会触发编译错误:
template <typename T> concept C = requires(T t){std::bool_constant<t>{};};
报错信息:
<source>:7:46: error: constraint variable 't' cannot be used in an evaluated context 7 | concept C = requires(T t){std::bool_constant<t>}; | ^
原因是requires表达式中的t是约束变量,不能直接用于常量表达式求值上下文。
正确的实现方式
我们需要验证:当创建一个非constexpr的T实例时,调用目标函数(这里是bool转换运算符)的结果能否作为常量表达式。可以通过constexpr lambda来实现这一点:
#include <type_traits> struct A {explicit constexpr operator bool() const {return true;}}; struct B {int x = 1; explicit constexpr operator bool() const {return x;}}; template <typename T> concept C = requires { // 在constexpr lambda中创建非constexpr实例,尝试常量上下文转换 std::bool_constant<[]() constexpr { T t; return static_cast<bool>(t); }()>{}; }; static_assert(C<A>); static_assert(!C<B>);
原理说明:
- 在constexpr lambda内部创建非constexpr的T对象
t - 尝试调用
t的转换运算符并返回结果 - 如果lambda能在constexpr上下文执行成功,说明转换运算符不依赖
t的非constexpr状态(即未使用t的非constexpr成员),std::bool_constant可正常实例化,Concept满足 - 对于结构体B,
t.x不是常量表达式,lambda无法在constexpr上下文执行,Concept不满足
如果要适配更通用的转换类型(不限于bool),可以改成模板化的Concept:
template <typename T, typename Ret> concept ConvertibleToConstexpr = requires { std::integral_constant<Ret, []() constexpr { T t; return static_cast<Ret>(t); }()>{}; }; // 使用示例 static_assert(ConvertibleToConstexpr<A, bool>); static_assert(!ConvertibleToConstexpr<B, bool>);
内容的提问来源于stack exchange,提问作者HolyBlackCat
相关产品推荐
相关产品推荐

