0

こんにちは私はTMPで遊んでいて、次のようなクラスを生成することを考えていました。

template<typename T, typename LogFunc>
class
{

(LogFuncはデフォルトで「nop」関数に設定する必要があります)

アイデアは、タイプTのインスタンスのいくつかの機能を定義するクラスを用意することです。たとえば、番号が偶数かどうかをチェックし、呼び出してログに記録するオプションもあります。

void memberFunc(T& t)
{
  LogFunc(t); 
}

または多分

void memberFunc(T& t)
{
  LogFunc lf;
  lf(t);
}

できますか?SOでAを読み取ることから、ラムダはtemplparamsとして問題があります。ところで、誰かがこれを気にかけているなら、これは私が試したものですが、それは印刷されます

:(

4

3 に答える 3

3

問題は、ラムダの型がコンパイラによって強制されるシングルトンであることです。ラムダ自体である値が 1 つだけあります。さらに、型には削除されたコンストラクターがあります。したがって、decltype を使用しても、テンプレートのインスタンス化の一部としてラムダを渡すことはできません。しかし、それらをコンストラクター引数として渡すことを妨げるものは何もありません。

ただし、ここで別の問題が発生します。コンストラクターの引数は、テンプレートのインスタンス化を推測するために使用されません (これが、標準ライブラリが make_pair や make_tuple などのユーティリティを提供する理由です)。したがって、テンプレート化されたファクトリ関数が必要です。

以上で、解決策は非常に簡単です。

template<typename T, typename LogFunc>
class Foo {
  public:
    Foo(const T& t, LogFunc fn) : t_(t), lfn_(fn) {}
    //...

  private:
    T t_;
    LogFunc lfn_;
};

struct Noop {
  template<typename...A>
  void operator()(A...) { };
};

template<typename T, typename LogFunc=Noop>
Foo<T, LogFunc> make_foo(const T& t, LogFunc func=LogFunc()) {
  return Foo<T, LogFunc>(t, func);
}
于 2012-10-30T18:29:49.963 に答える
2

これは直接的な答えにはなりませんが、あなたが何をしたかについて多くのヒントを与えてくれます。

LogFuncパラメーターは型 (オブジェクトではない) であるため、

  • LogFunc(t)パラメータとして一時的な指定を作成LogFunctます(実際にはコンストラクタを呼び出していますLogFunc::LogFunc(T&))。
  • LogFunc lf; lf(t);Logfunclf という名前の、スタックに存在するデフォルトの構築済みを作成し、そのメンバー関数をlf(t)呼び出します。LogFunc::operator()(T&)
  • LogFunc()(t)デフォルトで構築された一時的な LogFUnc を作成し、それに対して operator()(T&) を呼び出します。

ラムダについては、実際には、コンストラクターがキャプチャされた変数を受け取り、operator() が宣言したパラメーターを受け取るクラスです。ただし、それらはコンパイラの「内部」にのみ存在し、参照できる「名前」はありません。

あなたができることはdecltype、または自由関数でその型を推測することです。

通常、パラメトリック機能クラスは、構築時に初期化される関数オブジェクトを格納します。

#include <iostream>

template<class Fn>
class LogFunc
{
public:
    LogFunc(Fn f) :fn(f) {}

    template<class T>
    void memberFunc(T& t)
    { fn(t); }
private:
    Fn fn;
};

template<class Fn>
LogFunc<Fn> makeLogFunc(Fn f)
{ return LogFunc<Fn>(f); }

int main()
{
    int x=5;

    auto lf = makeLogFunc([](int& a){ std::cout << a << std::endl; });
    lf.memberFunc(x);

    return 0;
}

「g++ -pedantic -Wall -std=c++11」としてコンパイルし、出力します

5
于 2012-10-30T18:07:32.110 に答える
1

他の答えはすべて問題ありませんが、コンストラクター引数を . で渡すこともできますstd::function<T>。それは次のようになります。

#include <functional>
#include <iostream>

template <typename T> void someOther(T val){
  std::cout << "used other "<<val<<std::endl;
}

template <typename T> void noop(T val){
  std::cout << "noop "<<val<<std::endl;
}

template<typename T>
struct A{
  A(std::function<void(T)> f =noop<T> ) : mf(f){}
  void memberFunc(T valx){
    mf(valx);
  }
  std::function<void(T)> mf;
};

int main(){
  A<int> aNoop; ;
  A<float> aSomeOther{someOther<float>} ;
  aNoop.memberFunc(5);
  aSomeOther.memberFunc(3.55);
}

別の方法は、次のようにファンクター クラスを使用することです。

#include <iostream>
template <typename T> struct OtherC{
  void operator()(T v){ std::cout <<"other "<<v<<std::endl; };
};
template <typename T> struct NoopC{
  void operator()(T){ std::cout << "noop"<<std::endl; };
};
template<typename T, template <typename X> class F = NoopC >
struct A{
  static void memberFunc(T valx){ F<T>()(valx); }
};
int main(){
  A<int> aNoop; 
  A<float,OtherC> aSomeOther ;
  aNoop.memberFunc(5);
  aSomeOther.memberFunc(3.55);
}
于 2012-10-30T19:33:35.727 に答える