如何让带推导指南的wrap类同时支持constexpr和静态存储期变量作为非类型模板参数
问题解决方法
问题本质
你遇到的冲突本质是两种场景对wrap的存储要求互斥:
- 当传递
constexpr变量a1作为非类型模板参数(NTTP)时:wrap按值存储成员即可满足要求,但如果按引用存储,会因为a1是自动存储期的变量,不符合NTTP引用必须绑定到静态存储期对象的要求,导致编译失败。 - 当传递静态存储期的非
constexpr变量a2时:wrap按值存储会因为a2不是常量表达式,无法构造出符合要求的编译期常量wrap实例,只有按引用绑定到静态存储期的a2才能满足NTTP要求。
修复方案
给wrap添加带约束的双推导指南,让编译器自动根据传入参数的特性选择合适的推导结果:有constexpr属性的参数自动推导为值类型,非constexpr的静态存储期参数自动推导为引用类型,代码如下:
#include <type_traits> template <typename T> struct wrap { T thing; constexpr wrap(T thing) : thing(thing) {} }; // 优先级更高的推导指南:当参数可以构造constexpr的值类型wrap时,推导为值类型 template <typename T> wrap(const T& t) -> wrap<T> requires requires { constexpr wrap w(t); }; // fallback推导指南:不满足上面的条件时,推导为引用类型 template <typename T> wrap(const T& t) -> wrap<const T&>; template <wrap V> void fun() {} struct X { int a; }; int main() { constexpr auto a1 = &X::a; static const auto a2 = &X::a; fun<a1>(); // 自动匹配值类型推导 fun<a2>(); // 自动匹配引用类型推导 }
原理说明
- 带
requires约束的推导指南优先级高于无约束的推导指南,编译器会优先检查传入的参数是否能构造出constexpr的wrap值类型实例,如果可以就用值类型推导,适配constexpr变量的场景。 - 如果参数不满足值类型构造的要求,就自动fallback到引用类型的推导,适配静态存储期非
constexpr变量的场景。 - 整个过程不需要手动显式指定
wrap的模板参数,完全由CTAD自动完成推导。
注意:本方案依赖C++20及以上标准的特性,编译时需要指定对应标准(如gcc/clang加
-std=c++20参数,msvc加/std:c++20参数)。
内容的提问来源于stack exchange,提问作者lekner
相关产品推荐
相关产品推荐

