2

次のように、動作するコード。

#include <iostream>

template<class Detail>
class AbstractLogger
{
public:
    static void log(const char* str) {
        Detail::log_detailled(str);
    }
};

class Logger : public AbstractLogger<Logger>
{
public:
    static void log_detailled(const char* str) {
        std::cerr << str << std::endl;
    }
};

int main(void)
{
    AbstractLogger<Logger>::log("main function running!");
    return 0;
}

ここで、ライブラリに入れて、ライブラリユーザーに、ここのクラスAbstractLoggerのように自分のロガーを定義させたいと思います。Loggerこれには1つの欠点があります。AbstractLogger<Logger>ライブラリが認識できないため、ライブラリ内で使用できないことLoggerです。

ノート:

  • 仮想関数や質問はしないでください。また、「静的仮想」メンバーが無効であるという同様の問題を認識しています。たぶん、CRTPには回避策があります:)
  • C ++ 11は興味深いものですが、「通常の」C++が必要です。
4

3 に答える 3

2

正確なインスタンス化タイプを知らなくても、これをロギングメカニズムとして使用するライブラリが必要な場合は、それに対してアドバイスします。

他の要件を満たしながら(つまり、仮想関数を使用せずに)それを行う唯一の方法は、ログに記録する必要のあるライブラリ内のすべての関数/型を、その型をとるテンプレートに変換することLoggerです。最終的な結果として、ほとんどのインターフェイスがテンプレートになります(ただし、実装のかなりの部分をテンプレート化されていないコードに移動することはできますが、必要以上に困難になり、さらに大きなバイナリが生成されます) 。

仮想関数に関する懸念がパフォーマンスである場合は、アプローチとそれがもたらす問題を再検討する必要があります。特に、ロギング高価です。ほとんどのロギングライブラリは、(ログレベル/グループ/ ...が有効になっていない場合にロガーの呼び出しを回避するマクロを使用して)非ロギングのケースを最適化することでこれに取り組みますが、実際の書き込みには動的ディスパッチを残します。動的ディスパッチのコストは、コンソールやファイルへの書き込みのコスト、またはログに記録されるメッセージの生成のコストと比較してもごくわずかです(リテラル文字列をログに記録するだけではないと想定しています)

于 2012-10-12T19:55:04.870 に答える
1

通常のアプローチは、ユーザーがそれらの概念の1つ以上を満たす型を簡単に作成できるようにヘルパーを提供しながら、概念に対してコーディングすることです。例として、のようなものboost::iterator_facadeは、ユーザーがイテレーターを簡単に作成できるようにするCRTPヘルパーです。次に、そのイテレータは、イテレータが受け入れられる場所であればどこでも使用できます。たとえば、の範囲コンストラクタで使用できますstd::vector。その特定のコンストラクターがユーザー定義型の予知を持っていないことに注意してください。

あなたの場合、AbstractLoggerCRTPヘルパーになります。欠けている部分は、たとえばロガーの概念を定義することです。その結果、ロガーを必要とするすべてのものをテンプレートとして実装する必要があるか、任意のロガーを保持するための型消去コンテナーが必要であることに注意してください。

コンセプトチェック(Boostによって提供されるものなど)は、実際のコードでコンセプトを表すことができるため、この種のプログラミングに便利です。

于 2012-10-12T20:00:53.163 に答える
0

テンプレートクラスは、テンプレートパラメータの特殊化としてコンパイラによってインスタンス化されるため、「ライブラリに入れる」ことはできません。

ただし、テンプレートの実装で使用されるパラメーターに依存しないものをライブラリに入れることができます。

于 2012-10-12T19:55:48.603 に答える