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

谁说我不能喝 提交于 2019-12-06 04:33:37

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);
Mikael Persson

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.

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.

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