2

g関数ポインター、ファンクター、またはラムダを、渡された関数の引数の型を使用するテンプレート関数に渡す方法を探しています。次に例を示します。

template<class T1, class T2, class T3>
struct wrapper_t {
  boost::function<void(T1,T2,T3)> f;
  wrapper_t( boost::function<void(T1,T2,T3)> f ) : f(f) {}
  void operator( std::vector<T1> &a, std::vector<T2> &b, T3 c ) {
    assert(a.size() == b.size());
    for(size_t i = 0 ; i != a.size() ; i++) f(a[i], b[i], c);
  }
};
template<class T1, class T2, class T3>
wrapper_t<T1,T2,T3> make_wrapper( boost::function<void(T1,T2,T3)> f ) {
  return wrapper_t<T1,T2,T3>( f );
}

void f(int, double, char) {};
wrapper_t<int, double, char> w0(f); // need to repeat types

auto w1 = make_wrapper(f); // more comfortable

std::vector<int> a{{1, 2, 3}};
std::vector<double> b{{1.0, 2.0, 3.0}};
w0( a, b, 'c' );
w1( a, b, 'c' );

このmake_wrapper関数は、引数から型を抽出するためだけに存在し、型を 2 回入力する必要がないようにするための構文糖衣です。


私の問題の最小限の例は、次の関数です。

template<class T>
void g1( const boost::function<void(T)> & ) {}

これらを入力として使用する

void f1(int) {}
struct f2_t { void operator()(int) {} };

それは推論に失敗しますT=int

f2_t f2;
g1( f1 ); // mismatched types ‘const std::function<void(T)>’ and ‘void(int)’
g1( f2 ); // ‘f2_t’ is not derived from ‘const std::function<void(T)>’
g1( [](int){} ); // ‘::<lambda(int)>’ is not derived from ‘…
g1<int>( f1 ); // ok
g1<int>( f2 ); // ok
g1<int>( [](int){} ); // ok

ただしT=int、単純な関数ポインターから推測できますが、これはファンクターまたはラムダでも機能しません。

template<class T>
void g2( void (*)(T) ) {}

g2( f1 ); // ok
g2( f2 ); // mismatched types …
g2<int>( f2 ); // ok
g2( [](int){} ); // mismatched types …
g2<int>( [](int){} ); // ok

T単純な関数ポインターだけでなく、ファンクターとラムダも推論する方法はありますか?

それとも、このようなものでなければなりませんか?

template<class F>
void g( F ) { typedef first_argument_of<F>::type T; }

(私の実際のコードでは、このように 4 つの引数を持つ関数を分解する必要がありますstd::function::…argument_typeが、1 つまたは 2 つの引数に対してしか存在しませboost::functionん。上記などを参照)Ffunction

4

3 に答える 3

5

さまざまな理由で、あなたが望むことをする方法はありません。しかし、問題をかなり明確にする必要があるものを次に示します。

struct function_object
{
    template<typename ...T>
    void operator ()(T&&... v){}
};

f( function_object{} );

に渡される関数オブジェクトの引数の型はf? 任意の種類と数の引数で呼び出すことができます。

于 2013-06-19T01:22:18.953 に答える
1

OP が a を変更する関数を実際に取り、Tそれを a を変更する関数に変換したいというコメントを読んで、std::vector<T>これを行うには何が何であるかを知る必要があると考えているとしますT

あなたはそうしない

#include <type_traits>
#include <utility>

template<typename Lambda>
struct container_version {
  Lambda closure;
  container_version( container_version const& ) = default;
  container_version( container_version && ) = default;
  container_version( container_version & ) = default;

  template<typename U>
  container_version( U&& func ):closure(std::forward<U>(func)) {};

  // lets make this work on any iterable range:
  template<typename Container>
  void operator()( Container&& c ) const {
    for( auto&& x:c )
      closure(x);
  }
};

template<typename Lambda>
container_version< typename std::decay<Lambda>::type >
make_container_version( Lambda&& closure ) {
  return {std::forward<Lambda>(closure)};
}

#include <vector>
#include <iostream>
#include <functional>
#include <array>

int main() {
   std::vector<int> my_vec = {0, 1, 2, 3};
   for (auto x:my_vec)
      std::cout << x << ",";
   std::cout << "\n";
   make_container_version( []( int& x ) { x++; })( my_vec );

   for (auto x:my_vec)
      std::cout << x << ",";
   std::cout << "\n";

   // hey look, we can store it in a `std::function` if we need to:
   auto super_func = make_container_version( []( int& x ) { x++; } );
   std::function< void( std::vector<int>& ) > func = super_func;
   // and the same super_func can be used for a function on a different container:
   std::function< void( std::array<int,7>& ) > func2 = super_func;

   func(my_vec);
   for (auto x:my_vec)
      std::cout << x << ",";
   std::cout << "\n";
}

実際、引数を取得して に変換しstd::functionたり、強制的に に格納したりするとstd::function、効率が低下し、コードが複雑になり、実行に問題がないことが実行できなくなります。

にパックされる前の上記のバージョンは、s、s、s、raw配列、s などstd::functionを操作できます。setlistvectorCstd::array

于 2013-06-20T02:24:36.053 に答える