5

次のように、ラムダの型をテンプレート引数として使用することができます。

template<typename InArg, typename Function>
class selfCompose {
  Function f;
 public:
  selfCompose(Function f): f(f) {}
  auto operator() (InArg x) -> decltype(f(f(x))) {
    return f(f(x));                              }
};

int main() {
  auto f = [](int x){return x*x;};
  std::cout << selfCompose<int, decltype(f)>(f)(4)  //  yields (4²)² = 256
            << std::endl;
  return 0;
}

ただし、この二重の使用fは一種の冗長です。ラムダのをテンプレートとして渡すことを省略できます(適切なものにキャストしstd::functionます(多態性が失われますが、C ++ラムダはとにかくパラメトリックに多態的ではありません))が、私はそれを渡す必要がないことを望んでいるアプリケーションがありますコンストラクターへの(クラスの初期化自体をテンプレートパラメーターとして使用したいので、特定のコンストラクターシグネチャが必要です)。私はそれが次のように機能することを望みます

template<class InArg, class Function>
class selfCompose {
  Function f;
 public:
  selfCompose() {}  // default constructor for f
  auto operator() (InArg x) -> decltype(f(f(x))) {
    return f(f(x));                              }
};

int main() {
  auto f = [](int x){return x*x;};
  std::cout << selfCompose<int, decltype(f)>()(4) << std::endl;
  return 0;
}

ただし、ラムダにはデフォルトのコンストラクターが削除されているため、これはコンパイルされません。これはもちろんラムダをキャプチャするために避けられませんが、私の例のような単純なものの場合、これは私にはあまり意味がありません。ローカル変数を参照する必要はありません。

この機能を取得する他の方法はありますか、それともラムダを昔ながらの名前付きクラスとして定義することに頼る必要がありますか?

struct myFun {
  auto operator() (int x) -> int {return x*x;}
};

(もちろん、私が使用したいラムダ関数はそれほど単純ではないx → x²ので、いくつかの標準関数クラスから選択するだけでは十分な柔軟性がありません)

4

3 に答える 3

5

次のような関数の例に従うことができmake_pairますmake_shared

template<typename InArg, typename Function>
selfCompose<InArg, Function> make_selfCompose(Function f)
{
  return selfCompose<InArg, decltype(f)>(f);
}

int main() {
  auto f = [](int x){return x*x;};
  std::cout << make_selfCompose<int>(f)(4)
            << std::endl;
  return 0;
}
于 2012-11-16T15:57:26.127 に答える
1

がポリモーフィックになっている場合selfComposeは、パラメータタイプを明示的に渡す必要も、保存されているファンクタタイプを検査する必要もありません。後者は、多形ファンクターも処理できることを意味します。

template<typename Functor>
struct self_compose_type {
    // Omitting encapsulation for brevity
    Functor functor;

    // It is possible to overload operator() to deal
    // with all cv and ref qualifiers combinations
    template<typename... T>
    auto operator()(T&&... t)
    // Don't use std::result_of for the return type
    -> decltype( std::declval<Functor&>()(std::declval<T>()...) )
    { return functor(std::forward<T>(t)...); }
};

template<typename Functor>
self_compose_type<Functor>
self_compose(Functor&& functor)
{ return { std::forward<Functor>(functor) }; }

// C++03 style:
template<typename Functor>
self_compose_type<typename std::decay<Functor>::type>
make_self_compose(Functor&& functor)
{ return { std::forward<Functor>(functor) }; }

可変個引数を作成する必要はありません。必要に応じて、operator()引数を1つだけ受け入れるようにすることができます。

于 2012-11-17T03:55:16.530 に答える
-2

ベンジャミンはすでにあなたのケースのための素晴らしい回避策を投稿しました。あなたはそれを使うことができます。

私の解決策は、ラムダパラメータータイプを指定する必要がないベンジャミンの答えの改良版です。したがって、これを書く代わりに:

make_selfCompose<int>(f)(4); //Benjamin's solution

あなたはこれだけを書くことができます:

make_selfCompose(f)(4); //improved - absence `int` template argument.

make_selfComposeラムダパラメータタイプ自体を推測しましょう。

このソリューションでは、ファーストfunction_traitsクラスのテンプレートを次のように記述します。

#include <tuple>

template <typename T>
struct function_traits : public function_traits<decltype(&T::operator())>
{};

template <typename C, typename R, typename... A>
struct function_traits<R(C::*)(A...) const>
{
   template <size_t i>
   struct arg
   {
      typedef typename std::tuple_element<i, std::tuple<A...>>::type type;
   };
};

次に、次の改良版を示しmake_selfComposeます。

template<typename Fun> //<--- now it has one template parameter
selfCompose<typename function_traits<Fun>::template arg<0>::type, Fun>
make_selfCompose(Fun f)
{
  typedef typename function_traits<Fun>::template arg<0>::type InArg; //deduce it
  return selfCompose<InArg, decltype(f)>(f);
}

テストプログラムは次のとおりです。

int main() {
  auto f = [](int x){return x*x;};
  std::cout << make_selfCompose(f)(4)  //notice the relief here!
            << std::endl;
  return 0;
}

オンラインデモを見る

お役に立てば幸いです。:-)

于 2012-11-16T16:34:01.693 に答える