Is a pointer to a function which have unknown number of parameters possible?

妖精的绣舞 提交于 2019-12-22 13:31:47

问题


I am writing a simple class to measure performance of a function in terms of time . The user should be able to send a pointer to his function, parameters of the function, times to call the function and i will call the function, return the time elapsed. Here my problem is I dont know how many parameters the user's function takes! I thought to use variadic functions to get unknown number of parameters, however I still have the problem of declaring the function pointer that user passes as a parameter(because it doesnt have constant variable number) and not knowing the types of variables I recieve by using a variadic function.

It should not be hard, i guess :) All i want to do is to call a function which is not defined by me by using a function pointer.

Is there any way to solve these problems or?


回答1:


It doesn't really make sense to have a function-pointer to a function with unknown arguments. If you don't know how many arguments there are (let alone their types), how are you going to fill out the arguments at run-time?

The best you can do is require that the user's functions all have the same prototype, namely to take a va_list as a parameter, and require that your library provide your library with that same va_list (see also http://c-faq.com/varargs/handoff.html).

e.g.:

// Function-pointer type
typedef void (*func_t)(int, va_list);

// Your timer library function
void timer(func_t *p_func, ...)
{   
    va_list arg;
    va_start(arg, fmt);
    p_func(0, arg);
    va_end(arg);
}


// User's function
void user_function(int first_arg, va_list args)
{
   ...
};

// Invoke the timer library function
timer(&user_function, arg1, arg2, arg3);



回答2:


I think lambda functions can be used to do this:

template< typename Func >
unsigned int measure(Func f)
{
  // take time
  f();
  // take time
  return result;
}

void test_func_1(int i)            { std::cout << i; }
void test_func_2(std::ostream& os) { os << 42; }

int main()
{
  auto lambda_func_1 = [](){ test_func_1(42); };
  const unsigned int time_1 = measure( lambda_func_1 );
  std::cout << "calling test_func_1(42) took " << time_1 << " <unit>\n";

  auto lambda_func_2 = [](){ test_func_2(std::cerr); };
  const unsigned int time_2 = measure( lambda_func_2 );
  std::cout << "calling test_func_2(std::cout) took " << time_2 << " <unit>\n";

  return 0;
}

Of course, lambda functions will be part of C++ only after the next standard is released (hopefully this year), but quite a few compilers (among them GCC and VC) already implement them, so you have a chance to do it this way.


One might also make a function template employing variadic template arguments and perfect forwarding, passing the arguments of the function to be measured to the measuring function, which then passes them on. But I haven't played with this, so I can't write this up.




回答3:


Unfortunately, current C++ requires you to write a bunch of templates with varying lengths, one for each possible argument count. In principle, C++0x would allow you to use variadic templates like so:

template<typename Rv, typename Wrapper, typename... Args>
struct impl_wrapper {
    std::function<Rv (Args...)> func;

    Rv operator()(Args... args) const {
        Wrapper w;
        return func(args...);
    }

    impl_wrapper(const  std::function<Rv (Args...)> f)
        : func(f)
    {
    }
};

template<typename Wrapper>
struct wrap_func_ {
    template<typename Rv, typename... Args>
        impl_wrapper<Rv, Args...> operator()(const std::function<Rv (Args...)> &f)
        {
            return impl_wrapper<Rv, Wrapper, Args...>(f);
        }
};

template<typename Wrapper>
static wrap_func_<Wrapper> wrap_func;



struct test_wrapper {
    test_wrapper() {
        std::cout << "Begin call!\n";
    }

    ~test_wrapper() {
        std::cout << "End call!\n";
    }
};

int test_call(int x, char *y) {
    std::cout << y << x << std::endl;
    return x + 1;
}

int main() {
    std::function<int (int, char *)> f = test_call;
    f = wrap_func<test_wrapper>(f);

    std::cout << "Returned: " << f(42, "Prior to increment: ") << std::endl;
    return 0;
}

However, this requires support for features not yet implemented in G++, nor, most likely, in any other extant C++ compiler:

test.cpp:21: sorry, unimplemented: cannot expand ‘Args ...’ into a fixed-length argument list

Therefore, you must instead use template overloading for each possible argument count, up to some reasonable maximum.



来源:https://stackoverflow.com/questions/4972157/is-a-pointer-to-a-function-which-have-unknown-number-of-parameters-possible

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!