You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用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;
}

说明

  1. 非类型参数的常量要求:非类型模板参数必须是编译期常量,因此Bar和Bar::Inner中的变量需要声明为constexpr(或C++11中的const且用常量表达式初始化)。
  2. 辅助概念逻辑:
    • requires { std::addressof(Bar::Val) }:验证参数对应的变量是Bar命名空间的成员,能通过Bar::限定名访问。
    • !requires { std::addressof(Bar::Inner::Val) }:验证参数对应的变量不属于Bar::Inner子命名空间,无法通过该子命名空间的限定名访问。
  3. 主概念逻辑:通过折叠表达式(IsBarNonInnerMember<T, Sz> && ...)确保所有传入的非类型参数都满足约束。

内容的提问来源于stack exchange,提问作者Amolgorithm

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.16 02:13:22