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
と、コードをコンパイルできます。
コンパイラ エクスプローラでのライブ デモ