5

私が書いているコードの他のユーザーによって継承されることを意図した基本クラスがあり、抽象関数の 1 つがオブジェクトの名前を返します。プロジェクトの性質上、名前に空白を含めることはできません。

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

  • 派生クラスがコントラクトを破らないようにするには、仮想メソッドを変更して を返しno_wsます。

  • インターフェイスを維持したい (つまりconst char*、 を返す) 場合は、仮想メソッドをプライベートにし、それをパブリックの非仮想メソッドで呼び出します。ここ でその テクニック を 説明 します

もちろん、ここでは空白文字の有限セットのみをチェックしており、ロケールに依存しません。コンパイル時にロケールを処理するのは非常に難しいと思うので、名前で許可されている ASCII 文字のセットを明示的に指定する (ブラックリストではなくホワイトリスト) 方が (エンジニアリング的に) 良い方法かもしれません。

"Bad cat"空白が含まれているため、上記の例はコンパイルされません。クラスをコメントアウトするBad catと、コードをコンパイルできます。

コンパイラ エクスプローラでのライブ デモ

于 2021-06-10T18:07:28.940 に答える