2

I'm working on something like a small quick testing class that will take a function/functor to execute, and function/functor that generates input to the function to execute.

For example if the first function is sqrt(x) and the second one has a state and is doing counting, I want the class to execute

sqrt(0.0);  
sqrt(1.0);
...

for some number of iterations.

I can do that relatively easily (2 std::functions or templates) but how would one go about implementing that In case first function takes more than 1 argument? I can only think of forcing one function to take tuple, and forcing another to return tuple, but that looks ugly and forces interface on tested function.

EDIT:what I have now:

template <typename Func, typename ArgGen>
class Magic
{
    std::function<double (time_t)> time_to_frequency;
    std::set<decltype(Func()(ArgGen()()))> results_ok;
    std::set<decltype(Func()(ArgGen()()))> results_fail;
    ArgGen ag;
    Func f;
public:
    Magic(std::set<decltype(Func()(ArgGen()()))> results_ok, std::set<decltype(Func()(ArgGen()()))> results_fail,  std::function<double (const time_t)> time_to_frequency) : 
               results_ok(results_ok), results_fail(results_fail),  time_to_frequency(time_to_frequency)
    {}
    Magic() 
    {}
    void run(const int n)
    {
       bool success=true;
       for (int i=0; i< n; ++i)
       {
           auto rv = f(ag());
           const bool result_ok = results_ok.count(rv);
           if (result_ok)
           {
               printf(".");
           }
           else
           {
               success = false;
               std::cout << i <<": value unexpected "<< std::endl;
           }

       }
       std::cout << "run succeeded: " << std::boolalpha << success;
    }

};
NoSenseEtAl
  • 28,205
  • 28
  • 128
  • 277
  • Maybe with templates?! – Kerrek SB Sep 10 '13 at 08:31
  • 1
    Could you provide a code sample of what you want to achieve? – user1233963 Sep 10 '13 at 08:43
  • @KerrekSB like I said I can do it when first function takes only one argument, problem is when it takes >1 – NoSenseEtAl Sep 10 '13 at 08:43
  • 3
    Your question is unclear. Give an example of a non-unary function that you would want to use, and how you want to use it. – nikolas Sep 10 '13 at 08:45
  • The conditions under which the problem must be solved are totally unclear. Where you have issues solving this problem is also totally unclear. – Patrick Fromberg Sep 10 '13 at 08:53
  • Your sample confused me even more :( – user1233963 Sep 10 '13 at 08:56
  • It's still unclear what should happen if you use a non-unary function and why `std::bind` would not solve your problem – nikolas Sep 10 '13 at 08:57
  • if first function is int f(double a, double b, int c) how do I fwd return value of second function to it as parameters in generic way? Aka IDK the exact types or arity of first function and wnat to make it work for any matching pair of functions – NoSenseEtAl Sep 10 '13 at 09:01
  • 1
    @NoSenseEtAl well, C++ doesn't support multiple return values, so something like `std::tuple` seems to be your best bet here. If I now understand your problem correctly it's not getting the values into `Func`, but generically retrieving more than one value from `Gen` – nikolas Sep 10 '13 at 09:11
  • 3
    @NoSenseEtAl as nijansen said you can't have your generation function returning multiple values without a tuple. Though you can then unpack your tuple to call the test function using something like http://stackoverflow.com/questions/10766112/c11-i-can-go-from-multiple-args-to-tuple-but-can-i-go-from-tuple-to-multiple . To avoid modifying the test function. – user71404 Sep 10 '13 at 09:25

1 Answers1

1

I would have ArgGen return a tuple and then unpack the tuple with:

    #include <tuple>
    #include <iostream>

    template <class Func, class ... Args>
    struct invoke_from_tuple_helper
    {
        typedef decltype(std::declval<Func>()(std::declval<Args>()...)) return_type;

        template <unsigned total, std::size_t ... Indices>

        static return_type apply_helper(Func && f, std::tuple<Args...> && params,
                                 typename std::enable_if<total == sizeof...(Indices)>::type* =NULL)
        {
            return f(std::forward<Args>(std::get<Indices>(params))...);
        }

        template <unsigned total, std::size_t ... Indices>
        static return_type apply_helper(Func && f, std::tuple<Args...> && params,
                                 typename std::enable_if<(total > sizeof...(Indices)) >::type* =NULL)
        {
            return apply_helper<
                total, Indices..., sizeof...(Indices)>
                (std::forward<Func>(f), std::forward<std::tuple<Args...> >(params));
        }

        static return_type apply(Func && f, std::tuple<Args...> && params)
        {
            return apply_helper<sizeof...(Args)>(std::forward<Func>(f),
                                                 std::forward<std::tuple<Args...> >(params));
        }

    };

    template <class Func, class ... Args>
    typename invoke_from_tuple_helper<Func,Args...>::return_type
    invoke_from_tuple(Func && f, std::tuple<Args...>&&params)
    {
        return invoke_from_tuple_helper<Func,Args...>::apply(std::forward<Func>(f),
                                                             std::forward<std::tuple<Args...> >(params));
    }

    void f(int, long, std::tuple<int,long>)
    {
        std::cout << "I'm on the inside\n";
    }

    int main()
    {
        invoke_from_tuple(f, std::tuple<int,long,std::tuple<int,long> >());
        return 0;
    }

This was compiled and run with g++-4.8

SirGuy
  • 10,660
  • 2
  • 36
  • 66