1

数値のサインを計算する関数を作成しました。の場合、入力タイプを返しますstd::is_floating_point。しかしstd::is_integral、 の場合は を返しますdouble

template<class T , typename std::enable_if<std::is_integral<T>::value>::type* = nullptr >
double mysin(const T& t) // note, function signature is unmodified
{
    double a = t;
    return std::sin(a);
}

template<class T , typename std::enable_if<std::is_floating_point<T>::value>::type* = nullptr >
T mysin(const T& t) // note, function signature is unmodified
{
    return std::sin(t);
}

簡単です。vectorこれをs (または配列) とtuples (またはクラスター)で機能させたいと思います。となることによって:

(pseudo code:)
std::vector<std::double> a = mysin(std::vector<std::int>); 
std::tuple<std::double, std::float> b = mysin(std::tuple<std::int, std::float>);
std::vector<std::tuple<std::double, std::float>> c = mysin(std::vector<std::tuple<std::int, std::float>>);
std::tuple<std::vector<std::double>, std::float> d = mysin(std::tuple<std::vector<std::int>, std::float>);
std::tuple<std::tuple<std::double, std::vector<std::double>>, std::float>> e = mysin(std::tuple<std::tuple<std::int, std::vector<std::int>>, std::float>>);
and so on...

テンプレートに関するほとんどの例tupleでは、関数は戻り値を持たないか、累積値を返すか、または入力と同じ戻り値の型を持ちます。

私はこれらのトピックで多くのことを実験してきました (とりわけ) : +11 (STL)?

最後のものは特に役に立ちました。これはtuples では機能しますが、再帰tuples( tuples in tuples ) では機能しません。

最終的に (これが可能であれば)、 、 、 などを作成する必要がありますmycos。gcc mytan4.9.2myasinを使用します。

**編集:**これは、Yakk の提案と少しの調整の後に思いついたものです。

#include <utility>
#include <vector>
#include <memory>
#include <typeinfo> // used for typeid
#include <tuple>
#include <cstdlib> // for math functions?
#include <cmath> // for math functions
#include <type_traits> // for std::enable_if

template<class T , typename std::enable_if<std::is_integral<T>::value>::type* = nullptr >
double mysin(const T& t) { // note, function signature is unmodified
    double a = t;
    return std::sin(a);
// printing a debug string here will
// print tuple elements reversed!!
}


template<class T , typename std::enable_if<std::is_floating_point<T>::value>::type* = nullptr >
T mysin(const T& t) {// note, function signature is unmodified
// printing a debug string here will
// print tuple elements reversed!!
    return std::sin(t);
}

struct sine_t {
    template<class T>
    auto operator()(T&&t)const->
        decltype(mysin(std::declval<T>())) {
            return mysin(std::forward<T>(t));
            }
};

template<class F>
struct vectorize {
    template<class T,
        class R=std::vector< std::result_of_t< vectorize<F>(T const&) > >
    >
        R operator()( std::vector<T> const& v ) const {
            R ret;
            ret.reserve(v.size());
            for( auto const& e : v ) {
                ret.push_back( vectorize<F>{}(e) );
                }
        return ret;
        }

    template<
        class X,
        class R=std::result_of_t< F(X const&) >
    >
        R operator()( X const& x ) const {
            return F{}(x);
            }   

    template<
        class R, 
        class... Ts, 
        size_t... Is
    >
    R tup_help( std::index_sequence<Is...>, std::tuple<Ts...> const& t ) const {
        return std::make_tuple( vectorize<F>{}(std::get<Is>(t))... );
        }

    template<
        class... Ts,
        class R=std::tuple< std::result_of_t< vectorize<F>(Ts const&) >... >
    >
    R operator()( std::tuple<Ts...> const& t ) const {
        return tup_help<R>( std::index_sequence_for<Ts...>{}, t );
        }

    };

//+++++++++++++++++++++++++++++++++++++++++

int main() {
    std::vector<int> a = {1 ,2};
    std::tuple<int, double, int, double> b (42, -3.14, 42, -3.14);

    auto c = vectorize<sine_t>()(a);
    auto d = vectorize<sine_t>()(b);

    std::vector<std::tuple<int, int> > e {std::make_tuple(1 ,2)};
    //This does not not work:
    //auto f = vectorize<sine_t>()(e);

    //This works:
    std::tuple<std::vector<int> > g ( a );
    auto f = vectorize<sine_t>()(g);

    return 0;
}

これは機能します。C++14 が必要です。

4

1 に答える 1

1

まず、オーバーロード セット オブジェクト。これは、オーバーロード セット全体を単一のオブジェクトとして渡すことができるため便利です。

struct sine_t {
  template<class T>
  auto operator()(T&&t)const->
  decltype(mysin(std::declval<T>()))
  { return mysin(std::forward<T>(t)); }
};

次に、特定の関数オブジェクトを「ベクトル化」します。

簡単に始めましょう:

template<class F>
struct vectorize {
  template<class T, class R=std::vector< std::result_of_t< F(T const&) > >>
  R operator()( std::vector<T> const& v ) const {
    R ret;
    ret.reserve(v.size());
    for( auto const& e : v ) {
      ret.push_back( F{}(e) );
    }
    return ret;
  }
  template<class X, class R=std::result_of_t< F(X const&) >>
  R operator()( X const& x ) const {
    return F{}(x);
  }
};

これは 1 レベルの再帰をサポートし、std::vector.

ネストされたstd::vectors の無限再帰を許可するために、 のoperator()オーバーロードを変更しstd::vectorます。

  template<
    class T,
    class R=std::vector< std::result_of_t< vectorize<F>(T const&) > >
  >
  R operator()( std::vector<T> const& v ) const {
    R ret;
    ret.reserve(v.size());
    for( auto const& e : v ) {
      ret.push_back( vectorize<F>{}(e) );
    }
    return ret;
  }

そして今、私たちはサポートしていstd::vector<std::vector<int>>ます。

タプルのサポートのために、2 つの関数を追加します。最初のものには次の署名があります。

  template<
    class... Ts,
    class R=std::tuple< std::result_of_t< vectorize<F>(Ts const&) >... >
  >
  R operator()( std::tuple<Ts...> const& t ) const

これにより、戻り値が得られます (戦いの半分)。実際にマッピングを行うには、インデックス トリックを使用します。

  template<
    class R,
    class... Ts,
    size_t... Is
  >
  R tup_help( std::index_sequence<Is...>, std::tuple<Ts...> const& t ) const
  {
    return std::make_tuple( vectorize<F>{}(std::get<Is>(t))... );
  }
  template<
    class... Ts,
    class R=std::tuple< std::result_of_t< vectorize<F>(Ts const&) >... >
  >
  R operator()( std::tuple<Ts...> const& t ) const {
    return tup_help<R>( std::index_sequence_for<Ts...>{}, t );
  }

と raw C 配列の同様のコードがstd::array機能するはずです (raw C 配列をstd::array自然に変換します)。

std::index_sequenceなどは C++14 ですが、C++11 で数百の要素をサポートするバージョンを簡単に作成できます。(大きな配列をサポートするバージョンでは、より多くの作業が必要になります)。エイリアス (および同様のresult_of_tもの) も C++14 ですが、エイリアスは C++11 で簡単に記述できますtypename std::result_of<?>::type

最後に、あなたvectorize<sine_t>{}と何でも渡します。

関数オブジェクトの代わりに関数が必要な場合は、単純に作業を に委任してvectorize<sine_t>ください。

于 2015-03-12T19:20:47.830 に答える