user2428836
user2428836

Reputation:

Strange error when applying arguments from a vector to a function using variadic templates

I'm trying to make a function that takes a function and a vector and applies the function to the arguments from the vector, something like

f([](int x, int y) {return x+y;}, {1, 2}); \\returns 3

my current code looks like this:

#include <iostream>
#include <vector>
#include <functional>
#include <type_traits>
#include <boost/type_traits.hpp>

template <std::size_t... Indices>
    struct indices {
    using next = indices<Indices..., sizeof...(Indices)>;
};
template <std::size_t N>
struct build_indices {
    using type = typename build_indices<N-1>::type::next;
};
template <>
struct build_indices<0> {
    using type = indices<>;
};
template <std::size_t N>
using BuildIndices = typename build_indices<N>::type;

template <size_t num_args>
struct unpack_caller
{
private:
    template <typename FuncType, size_t... I>
    typename std::result_of<FuncType>::type call(FuncType &f, std::vector<int> &args,     indices<I...>){
        return f(args[I]...);
    }

public:
    template <typename FuncType>
    typename std::result_of<FuncType>::type operator () (FuncType &f, std::vector<int>     &args)
    {
        return call(f, args, BuildIndices<num_args>{});
    }
}; 

template<typename InnerType, typename ...Args>
class MFA
{
    std::function<InnerType(Args...)> func;
public:
    MFA(InnerType f(Args...))
        : func(f)
    {}

    virtual InnerType calc(std::vector<InnerType> & x)
    {
        return unpack_caller<sizeof...(Args)>()(func, x);
    }
};


int main()
{
    auto fun1 = MFA<int, int, int>([](int x, int y) {return x + y; });
    std::vector<int> arg = std::vector<int>({1, 2});
    fun1.calc(arg);

   return 0;
}

and it gives an error (GCC 4.8.1):

$g++ -std=c++0x main.cpp -o demo -lm -pthread -lgmpxx -lgmp -lreadline 2>&1
main.cpp: In instantiation of 'InnerType MFA<InnerType,     Args>::calc(std::vector<InnerType>&) [with InnerType = int; Args = {int, int}]':
main.cpp:68:18: required from here
main.cpp:57:50: error: no match for call to '(unpack_caller<2ul>)     (std::function<int(int, int)>&, std::vector<int>&)'
return unpack_caller<sizeof...(Args)>()(func, x);
^
main.cpp:25:8: note: candidate is:
struct unpack_caller
^
main.cpp:35:45: note: template<class FuncType> typename std::result_of<FuncType>::type     unpack_caller<num_args>::operator()(FuncType&, std::vector<int>&) [with FuncType =     FuncType; long unsigned int num_args = 2ul]
typename std::result_of<FuncType>::type operator () (FuncType &f, std::vector<int>     &args)
^
main.cpp:35:45: note: template argument deduction/substitution failed:
main.cpp: In substitution of 'template<class FuncType> typename     std::result_of<FuncType>::type unpack_caller<num_args>::operator()(FuncType&,     std::vector<int>&) [with FuncType = FuncType; long unsigned int num_args = 2ul] [with     FuncType = std::function<int(int, int)>]':
main.cpp:57:50: required from 'InnerType MFA<InnerType,     Args>::calc(std::vector<InnerType>&) [with InnerType = int; Args = {int, int}]'
main.cpp:68:18: required from here
main.cpp:35:45: error: invalid use of incomplete type 'class     std::result_of<std::function<int(int, int)> >'
In file included from /usr/local/gcc-4.8.1/include/c++/4.8.1/bits/move.h:57:0,
from /usr/local/gcc-4.8.1/include/c++/4.8.1/bits/stl_pair.h:59,
from /usr/local/gcc-4.8.1/include/c++/4.8.1/bits/stl_algobase.h:64,
from /usr/local/gcc-4.8.1/include/c++/4.8.1/bits/char_traits.h:39,
from /usr/local/gcc-4.8.1/include/c++/4.8.1/ios:40,
from /usr/local/gcc-4.8.1/include/c++/4.8.1/ostream:38,
from /usr/local/gcc-4.8.1/include/c++/4.8.1/iostream:39,
from main.cpp:1:
/usr/local/gcc-4.8.1/include/c++/4.8.1/type_traits:1878:11: error: declaration of     'class std::result_of<std::function<int(int, int)> >'
class result_of;

How can I correct it? The function MFA::calc must have the type it has now as MFA is supposed to be an implementation of an interface.

EDIT: I've been using code from following stackoverflow questions: Any Solution to Unpack a Vector to Function Arguments in C++? Initialize std::array with a range (pair of iterators)

Upvotes: 1

Views: 366

Answers (1)

Daniel Frey
Daniel Frey

Reputation: 56863

You can't use std::result_of<FuncType>::type, you would need to add the arguments, e.g. std::result_of<FuncType(int,int)>::type. In your case, this is a more difficult than the alternative, hence I suggest you use:

template <size_t num_args>
struct unpack_caller
{
private:
    template <typename FuncType, size_t... I>
    auto call(FuncType &f, std::vector<int> &args, indices<I...>)
      -> decltype( f(args[I]...) )
    {
        return f(args[I]...);
    }

public:
    template <typename FuncType>
    auto operator () (FuncType &f, std::vector<int> &args)
      -> decltype( std::declval<unpack_caller<num_args>>().call(f, args, BuildIndices<num_args>{}) )
    {
        return call(f, args, BuildIndices<num_args>{});
    }
};

Live example

Note that with C++14, you could leave out the -> decltype(...) part and simply rely on auto alone.

Upvotes: 1

Related Questions