如果字符串有空格,则引发编译时错误
Raise compile-time error if a string has whitespace
我有一个基础 class 打算由我正在编写的代码的其他用户继承,并且其中一个抽象函数 returns 是对象的名称。由于项目的性质,名称不能包含空格。
class MyBaseClass {
public:
// Return a name for this object. This should not include whitespace.
virtual const char* Name() = 0;
};
有没有办法在编译时检查 Name()
函数的结果是否包含空格?我知道 constexpr
函数可以进行编译时操作,但我不确定向代码用户发出信号的正确方法是他们的函数 returns 是一个顽皮的字符串。
我也不清楚如何让编译器实际执行一个 constexpr
函数来执行这样的检查(如果 constexpr
甚至可以解决这个问题)。
除非名称本身都在编译时指定,否则无法在运行时检查之前断言它们不包含空白字符。
我认为这在 C++20 中是可能的。
这是我的尝试:
#include <string_view>
#include <algorithm>
#include <stdexcept>
constexpr bool is_whitespace(char c) {
// Include your whitespaces here. The example contains the characters
// documented by https://en.cppreference.com/w/cpp/string/wide/iswspace
constexpr char matches[] = { ' ', '\n', '\r', '\f', '\v', '\t' };
return std::any_of(std::begin(matches), std::end(matches), [c](char c0) { return c == c0; });
}
struct no_ws {
consteval no_ws(const char* str) : data(str) {
std::string_view sv(str);
if (std::any_of(sv.begin(), sv.end(), is_whitespace)) {
throw std::logic_error("string cannot contain whitespace");
}
}
const char* data;
};
class MyBaseClass {
public:
// Return a name for this object. This should not include whitespace.
constexpr const char* Name() { return internal_name().data; }
private:
constexpr virtual no_ws internal_name() = 0;
};
class Dog : public MyBaseClass {
constexpr no_ws internal_name() override {
return "Dog";
}
};
class Cat : public MyBaseClass {
constexpr no_ws internal_name() override {
return "Cat";
}
};
class BadCat : public MyBaseClass {
constexpr no_ws internal_name() override {
return "Bad cat";
}
};
这里有几个想法:
让我们将类型系统用作文档和约束。因此,让我们创建一个 class(上例中的 no_ws
)来表示 没有空格的字符串 .
对于在编译时强制执行约束的类型,它必须在编译时评估其构造函数。所以让我们构造构造函数 consteval
.
为确保派生的classes不违约,修改虚方法为return no_ws
.
如果你想保留接口(即 returning const char*
),将虚拟方法设为私有,并在 public 非虚拟方法。该技术已解释 here。
当然,现在我只检查一组有限的空白字符,并且与语言环境无关。我认为在编译时处理语言环境会非常棘手,所以也许更好的方法(工程方面)是明确指定名称中允许的一组 ASCII 字符(白名单而不是黑名单)。
以上示例无法编译,因为 "Bad cat"
包含空格。注释掉 Bad cat
class 将允许代码编译。
我有一个基础 class 打算由我正在编写的代码的其他用户继承,并且其中一个抽象函数 returns 是对象的名称。由于项目的性质,名称不能包含空格。
class MyBaseClass {
public:
// Return a name for this object. This should not include whitespace.
virtual const char* Name() = 0;
};
有没有办法在编译时检查 Name()
函数的结果是否包含空格?我知道 constexpr
函数可以进行编译时操作,但我不确定向代码用户发出信号的正确方法是他们的函数 returns 是一个顽皮的字符串。
我也不清楚如何让编译器实际执行一个 constexpr
函数来执行这样的检查(如果 constexpr
甚至可以解决这个问题)。
除非名称本身都在编译时指定,否则无法在运行时检查之前断言它们不包含空白字符。
我认为这在 C++20 中是可能的。
这是我的尝试:
#include <string_view>
#include <algorithm>
#include <stdexcept>
constexpr bool is_whitespace(char c) {
// Include your whitespaces here. The example contains the characters
// documented by https://en.cppreference.com/w/cpp/string/wide/iswspace
constexpr char matches[] = { ' ', '\n', '\r', '\f', '\v', '\t' };
return std::any_of(std::begin(matches), std::end(matches), [c](char c0) { return c == c0; });
}
struct no_ws {
consteval no_ws(const char* str) : data(str) {
std::string_view sv(str);
if (std::any_of(sv.begin(), sv.end(), is_whitespace)) {
throw std::logic_error("string cannot contain whitespace");
}
}
const char* data;
};
class MyBaseClass {
public:
// Return a name for this object. This should not include whitespace.
constexpr const char* Name() { return internal_name().data; }
private:
constexpr virtual no_ws internal_name() = 0;
};
class Dog : public MyBaseClass {
constexpr no_ws internal_name() override {
return "Dog";
}
};
class Cat : public MyBaseClass {
constexpr no_ws internal_name() override {
return "Cat";
}
};
class BadCat : public MyBaseClass {
constexpr no_ws internal_name() override {
return "Bad cat";
}
};
这里有几个想法:
让我们将类型系统用作文档和约束。因此,让我们创建一个 class(上例中的
no_ws
)来表示 没有空格的字符串 .对于在编译时强制执行约束的类型,它必须在编译时评估其构造函数。所以让我们构造构造函数
consteval
.为确保派生的classes不违约,修改虚方法为return
no_ws
.如果你想保留接口(即 returning
const char*
),将虚拟方法设为私有,并在 public 非虚拟方法。该技术已解释 here。
当然,现在我只检查一组有限的空白字符,并且与语言环境无关。我认为在编译时处理语言环境会非常棘手,所以也许更好的方法(工程方面)是明确指定名称中允许的一组 ASCII 字符(白名单而不是黑名单)。
以上示例无法编译,因为 "Bad cat"
包含空格。注释掉 Bad cat
class 将允许代码编译。