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
相关产品推荐
相关产品推荐

