c++ - 当构造函数输入包含重复项时创建编译器错误
问题描述
考虑以下类:
class Base {
public:
Base(const std::initializer_list<const char*>& words)
: words_(words) {}
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"}){} // do not want to allow duplicates at compile time
};
我最初的方法是尝试模板化 Base 类。但是,据我确定,我不能使用非类型模板参数,即使在可以将字符串作为参数传递的 C++20 中(我相信在 C++20 方法中您只能传递一个字符串)。
我的下一个方法是编写一个 constexpr 函数来确定单词是否唯一
constexpr bool unique_words(const std::initializer_list<const char*>& words);
然后重写Base类如下:
class Base {
public:
constexpr Base(const std::initializer_list<const char*>& words)
: words_(words)
{
static_assert(unique_words(words));
}
std::initializer_list<const char*> words_;
};
尽管此函数在类外部工作,但在 Base 构造函数内部,编译器告诉我不能将构造函数参数的值用作常量。当然,我可以编写一个运行时检查,但我真的想阻止在编译时在初始化列表中创建重复的单词。这可能吗?
解决方案
要检查任何内容,您必须 constexpr 构造该类。要在 constexpr 函数中触发编译时错误,您可以抛出,请参阅Generate compile-time error if compile-time-constant parameter is wrong。
#include <initializer_list>
#include <type_traits>
#include <array>
#include <stdexcept>
template<std::size_t N>
constexpr bool unique_words(const std::array<const char*, N>& words) {
// TODO: implement real logic here
return words[0][0] == 'd';
}
template<std::size_t N>
struct Base {
constexpr Base(const std::array<const char*, N>& words)
: words_(words)
{
if (!unique_words<N>(words)) {
throw std::invalid_argument("Base must take unique words!");
}
}
std::array<const char*, N> words_;
};
struct Derived_BAD : public Base<4> {
constexpr Derived_BAD() : Base{{"e", "car", "time", "car"}} {}
};
int main() {
constexpr Derived_BAD var; // compile-time error - can't throw in constexpr
Derived_BAD var2; // will throw at runtime
}
不要存储std::initializer_list
在你的课堂上!!请参阅使用 std::initializer_list 作为成员变量。
不构造时无法进行编译时检查constexpr
。如果您真的想检查这种情况,您可以使用 GNU__builtin_constant_p
扩展并启用编译器优化,请参阅 GNU 文档和启用静态检查以进行常量评估和如何在常量评估表达式中获得编译时错误?.
推荐阅读
- php - 在奏鸣曲的嵌套模态 crud 中打开 Ckeditor 时未加载
- ios - 如何在开发的实时聊天应用程序中共享一些页面详细信息作为链接
- assembly - 将多个变量连接成一个字符串
- android - 缩放会导致像素化矢量绘图
- javascript - 我的画布中的触摸事件没有按预期工作,我无法确定它不工作的原因
- thymeleaf - 使用 Thymeleaf 3 在自定义属性中转义 & 符号?
- django - 如何在 django 中发送密码重置电子邮件时显示公司名称而不是电子邮件地址
- linux-kernel - 什么是内核映像?为什么它在嵌入式中是强制性的?
- firebase - 如何在 python 中增加 Firestore 字段值?
- java - 从片段更改工具栏