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

C++如何让构造函数initializer_list参数含重复值时触发编译错误

错误原因说明

你原有写法报错的核心原因是:static_assert要求其参数必须是编译期常量表达式,而构造函数的入参哪怕是在constexpr构造函数中,也属于运行时可修改的参数,不属于编译期常量范畴,因此无法直接用于static_assert校验。


可行实现方案

方案1:C++20 constexpr构造+异常触发编译报错(最小改造成本)

利用C++20的规则:constexpr函数在编译期执行时如果抛出异常,会直接触发编译错误。这种方案不需要修改原有构造的传参写法,改造成本最低:

#include <initializer_list>
#include <string_view>

// 编译期判断字符串列表是否唯一
constexpr bool unique_words(std::initializer_list<std::string_view> words) noexcept {
    for (auto it = words.begin(); it != words.end(); ++it) {
        for (auto jt = it + 1; jt != words.end(); ++jt) {
            if (*it == *jt) return false;
        }
    }
    return true;
}

class Base {
public:
    constexpr Base(const std::initializer_list<const char*>& words) 
        : words_(words)
    {
        // 编译期执行时不满足条件就抛出异常,直接触发编译错误
        if (!unique_words({words.begin(), words.end()})) {
            throw "found duplicate string in initializer list";
        }
    }
    std::initializer_list<const char*> words_;
};

// 合法派生类,编译通过
class Derived_OK : public Base
{
public:
    // 构造函数加constexpr强制编译期执行校验
    constexpr Derived_OK()
        : Base({ "dog", "car", "time"}){}
};

// 非法派生类,编译直接报错
class Derived_BAD : public Base
{
public:
    constexpr Derived_BAD()
        : Base({ "dog", "car", "time", "car"}){}
};

适用场景:使用C++20及以上标准,不想修改原有构造传参写法。


方案2:非类型模板参数传字符串(100%编译期强校验)

如果要彻底杜绝运行时才触发检查的可能,可以把字符串作为非类型模板参数传入,利用C++20的约束直接在编译期做校验:

#include <initializer_list>
#include <string_view>
#include <cstring>

constexpr bool unique_words(std::initializer_list<std::string_view> words) noexcept {
    for (auto it = words.begin(); it != words.end(); ++it) {
        for (auto jt = it + 1; jt != words.end(); ++jt) {
            if (*it == *jt) return false;
        }
    }
    return true;
}

// 字符串字面量包装器,用于作为非类型模板参数
template<size_t N>
struct StringLiteral {
    constexpr StringLiteral(const char (&str)[N]) noexcept {
        __builtin_memcpy(value, str, N);
    }
    char value[N];
    constexpr operator std::string_view() const noexcept {
        return {value, N-1};
    }
};

class Base {
public:
    // 用C++20约束直接在模板层面做唯一性检查
    template<StringLiteral... Strs>
    requires (unique_words({std::string_view(Strs)...}))
    Base() : words_({Strs.value...}) {}

    std::initializer_list<const char*> words_;
};

// 合法派生类,编译通过
class Derived_OK : public Base
{
public:
    Derived_OK() : Base<"dog", "car", "time">() {}
};

// 非法派生类,编译直接报错,提示模板约束不满足
class Derived_BAD : public Base
{
public:
    Derived_BAD() : Base<"dog", "car", "time", "car">() {}
};

适用场景:需要确保无论什么构造场景都不会漏过检查,可接受修改构造传参写法。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.01 18:57:01