1. ホーム
  2. c++

[解決済み] あるクラスが指定されたシグネチャのメンバ関数を持つかどうかを確認する

2022-04-27 09:55:30

質問

あるクラスが与えられたシグネチャの特定のメンバー関数を持っているかどうかを検出するテンプレートのトリックについて質問しています。

この問題は、ここに引用されているものと似ています http://www.gotw.ca/gotw/071.htm Sutterの本の項目で、彼は質問に対して、クラスCは特定のシグネチャを持つメンバー関数を提供しなければならない、さもなければプログラムはコンパイルされないと答えています。私の問題では、クラスがその関数を持っている場合に何かをする必要があり、そうでない場合は "他の何かをする必要があります。

同じような問題にboost::serializationが直面しましたが、私は彼らが採用した解決策が好きではありません。特定のシグネチャを持つメンバー関数(彼らの場合は与えられた型の2つのパラメータを受け取る "serialize")を定義しない限り、デフォルトで(あなたが定義しなければならない)自由関数を呼び出すテンプレート関数で、さもなければコンパイルエラーが発生するのです。つまり、侵入的なシリアライズと非侵入的なシリアライズの両方を実装しているのです。

私は2つの理由から、この解決策は好きではありません。

  1. boost::serialization名前空間にあるグローバルな"serialize"関数をオーバーライドしなければならないので、あなたのクライアントコードの中で名前空間boostと名前空間serializationを開かなければならないのです!押し付けにならないようにするために。
  2. その解決のためのスタックは は10~12回の関数呼び出しが必要でした。

私はそのメンバー関数を持っていないクラスのためにカスタム動作を定義する必要があり、私の実体は異なるネームスペース内にあります(そして、私は別のものにいる間、あるネームスペースで定義されたグローバル関数をオーバーライドしたくありません)。

このパズルを解くためのヒントを教えてください。

解き方は?

SFINAEを利用することで、コンパイル時に関数の存在を検出することができます。私のコードの例(クラスがメンバ関数 size_t used_memory() const を持つかどうかをテストします)。

template<typename T>
struct HasUsedMemoryMethod
{
    template<typename U, size_t (U::*)() const> struct SFINAE {};
    template<typename U> static char Test(SFINAE<U, &U::used_memory>*);
    template<typename U> static int Test(...);
    static const bool Has = sizeof(Test<T>(0)) == sizeof(char);
};

template<typename TMap>
void ReportMemUsage(const TMap& m, std::true_type)
{
        // We may call used_memory() on m here.
}
template<typename TMap>
void ReportMemUsage(const TMap&, std::false_type)
{
}
template<typename TMap>
void ReportMemUsage(const TMap& m)
{
    ReportMemUsage(m, 
        std::integral_constant<bool, HasUsedMemoryMethod<TMap>::Has>());
}