问题
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