5

我有一个基类,旨在由我正在编写的代码的其他用户继承,其中一个抽象函数返回对象的名称。由于项目的性质,名称不能包含空格。

class MyBaseClass {

  public:

    // Return a name for this object. This should not include whitespace.
    virtual const char* Name() = 0;

};

有没有办法在编译时检查Name()函数的结果是否包含空格?我知道函数可以进行编译时操作,constexpr但我不确定向代码用户发出信号的正确方法,即他们的函数返回一个顽皮的字符串。

我也不清楚如何让constexpr编译器实际执行一个函数来执行这样的检查(如果constexpr是这样的话)。

4

2 回答 2

7

我认为这在 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";
    }
};

这里有几个想法:

  • 让我们使用类型系统作为文档和约束。因此,让我们创建一个no_ws表示没有空格的字符串的类(在上面的示例中) 。

  • 对于在编译时强制执行约束的类型,它必须在编译时评估其构造函数。因此,让我们制作构造函数consteval

  • 为确保派生类不会违反约定,请将虚方法修改为 return no_ws

  • 如果要保留接口(即返回const char*),请将虚拟方法设为私有,并在公共非虚拟方法中调用它。该技术在此处进行了说明。

当然,现在我只检查一组有限的空白字符,并且与语言环境无关。我认为在编译时处理语言环境会非常棘手,所以也许更好的方法(工程方面)是明确指定名称中允许的一组 ASCII 字符(白名单而不是黑名单)。

上面的示例无法编译,因为"Bad cat"包含空格。注释掉Bad cat类将允许代码编译。

Compiler Explorer 上的现场演示

于 2021-06-10T18:07:28.940 回答
1

除非名称本身都是在编译时指定的,否则无法在运行时检查之前断言它们不包含空白字符。

于 2021-06-10T17:40:06.510 回答