如何用C++概念限制非类型模板参数仅属于Bar命名空间而非Inner?
问题
我定义了如下命名空间结构:
namespace Bar { constexpr size_t num = 32; namespace Inner { constexpr size_t num = 4; }; };
同时有一个可变参数函数模板foo,要求其接收的同类型非类型模板参数必须是Bar命名空间的直接成员,且不能属于Bar::Inner子命名空间:
template<typename T, T ...Sz> requires MyConcept<T, Sz...> auto foo() { return (Sz + ...); }
需要实现MyConcept概念来完成这个约束。
解决方案
要实现该约束,我们可以先定义一个检查单个非类型参数的辅助概念,再通过折叠表达式将约束应用到所有可变参数上:
完整代码实现
#include <type_traits> namespace Bar { constexpr size_t num = 32; namespace Inner { constexpr size_t num = 4; }; }; // 辅助概念:验证单个非类型参数是Bar的直接成员,且不属于Bar::Inner template<typename T, T Val> concept IsBarNonInnerMember = requires { // 确保参数对应的变量能通过Bar::限定名访问(属于Bar命名空间) { std::addressof(Bar::Val) } -> std::same_as<const T*>; } && !requires { // 确保参数对应的变量不能通过Bar::Inner::限定名访问(不属于Inner子命名空间) std::addressof(Bar::Inner::Val); }; // 主概念:对所有可变参数应用单个参数的约束 template<typename T, T ...Sz> concept MyConcept = (IsBarNonInnerMember<T, Sz> && ...); // 目标函数模板 template<typename T, T ...Sz> requires MyConcept<T, Sz...> auto foo() { return (Sz + ...); } // 测试示例 int main() { // 合法:使用Bar::num auto valid_result = foo<size_t, Bar::num>(); // 返回32 // 以下代码会触发编译错误,符合约束要求 // auto invalid_inner = foo<size_t, Bar::Inner::num>(); // size_t global_var = 10; // auto invalid_global = foo<size_t, global_var>(); return 0; }
说明
- 非类型参数的常量要求:非类型模板参数必须是编译期常量,因此
Bar和Bar::Inner中的变量需要声明为constexpr(或C++11中的const且用常量表达式初始化)。 - 辅助概念逻辑:
requires { std::addressof(Bar::Val) }:验证参数对应的变量是Bar命名空间的成员,能通过Bar::限定名访问。!requires { std::addressof(Bar::Inner::Val) }:验证参数对应的变量不属于Bar::Inner子命名空间,无法通过该子命名空间的限定名访问。
- 主概念逻辑:通过折叠表达式
(IsBarNonInnerMember<T, Sz> && ...)确保所有传入的非类型参数都满足约束。
内容的提问来源于stack exchange,提问作者Amolgorithm
相关产品推荐
相关产品推荐

