3

関数が複数の値を返すようにしたい場合があります。C++ でこのような動作を実現するための非常に一般的な方法の 1 つは、非 const 参照によって値を渡し、関数で値を代入することです。

void foo(int & a, int & b)
{
    a = 1; b = 2;
}

どちらを使用しますか:

int a, b;
foo(a, b);
// do something with a and b

今、私はそのような関数を受け入れ、セット引数を結果を返す別の関数に転送したいファンクタを持っています:

template <typename F, typename G>
struct calc;

template <
    typename R, typename ... FArgs,
    typename G
>
struct calc<R (FArgs...), G>
{
    using f_type = R (*)(FArgs...);
    using g_type = G *;

    R operator()(f_type f, g_type g) const
    {
        // I would need to declare each type in FArgs
        // dummy:
        Args ... args;
        // now use the multiple value returning function
        g(args...);
        // and pass the arguments on
        return f(args...);
    }
};

このアプローチは理にかなっていますか、それともタプルベースのアプローチを使用する必要がありますか? ここでタプルベースのアプローチよりも賢いものはありますか?

4

2 に答える 2

2

コンパイル時のインデックスを使用できます。

template< std::size_t... Ns >
struct indices
{
    typedef indices< Ns..., sizeof...( Ns ) > next;
};

template< std::size_t N >
struct make_indices
{
    typedef typename make_indices< N - 1 >::type::next type;
};

template<>
struct make_indices< 0 >
{
    typedef indices<> type;
};

template< typename F, typename G >
struct calc;

template<
   typename R, typename ... FArgs,
   typename G
>
struct calc< R (FArgs...), G >
{
   using f_type = R (*)(FArgs...);
   using g_type = G *;

private:
   template< std::size_t... Ns >
   R impl(f_type f, g_type g, indices< Ns... > ) const
   {
      std::tuple< FArgs ... > args;
      g( std::get< Ns >( args )... );

      // alternatively, if g() returns the tuple use:
      // auto args = g();

      return f( std::get< Ns >( args )... );
   }

public:
   R operator()(f_type f, g_type g) const
   {
      return impl( f, g, typename make_indices< sizeof...( FArgs ) >::type() );
   }
};
于 2013-09-11T09:13:47.933 に答える
1

fとの両方の署名を でg動作するように変更しているという事実を受け入れるとstd::tuple、この問題の答えは簡単になります。

template <typename F, typename G> struct calc;

template <typename R, typename ... Args>
struct calc<R (std::tuple<Args...> const &), std::tuple<Args...> ()>
{
    using f_type = R (*)(std::tuple<Args...> const &);
    using g_type = std::tuple<Args...> (*)();

    R operator()(f_type f, g_type g) const
    {
        return f(g());
    }
};

簡単な例を次に示します。

int sum(std::tuple<int, int> const & t) { return std::get<0>(t) + std::get<1>(t); }
std::tuple<int, int> gen() { return std::make_tuple<int, int>(1, 2); }

auto x = calc<decltype(sum), decltype(gen)>()(&sum, &gen);

ただし、このソリューションの制限は明らかです。独自の関数を作成する必要があります。このアプローチでは as のようなものを使用することはできませstd::powん。f

于 2013-09-11T08:52:16.080 に答える