I'm trying to create function which takes variadic function as parameter, but I can't figure out how to do it in a proper way. This is my try:
#include <iostream>
#include <cstdarg>
using namespace std;
int add(int args, ...) {
int res = 0;
va_list ap;
va_start(ap, args);
for(int i=0; i < args; ++i)
res += va_arg(ap, int);
va_end(ap);
return res;
}
int func(int (*func_arg)(int args, ...)) {
return func_arg; //error
}
int main() {
cout << add(2, 1, 2) << endl; //working
cout << func(add(2, 1, 2)); //error
return 0;
}
This here...
func(add(2, 1, 2))
... calls the function add and tries to pass the result into func. That's making a pointer out of an integer without a cast, etc. So you get an error.
To pass the function itself (after the suitable function to pointer conversion) you'd do this:
func(add)
However, your implementation of func tries to return an integer by converting the function pointer. I strongly suspect that's not what you want. If you intend to call the variadic function, you can do this:
int func(int (*func_arg)(int args, ...)) {
return func_arg(2, 1, 2);
}
But that of course hard-codes the arguments. You'd need to work out a slight design change if you wish to allow passing arguments as well.
Having said all that, if you wish to support callers of func passing in anything that may return an integer, you can use the library type std::function to accomplish that. Then your function will become something like this:
int func(std::function<int()> func_arg) {
return func_arg(); //Invoke the callable
}
And the call site will be able to adapt to it with a simple lambda:
func([]{ return add(2, 1, 2); })
Which will come together into the effect you seem intent on achieving.
Related
I've written (and use) my own string formatting function and I'd like to simplify the usage of the function, in a specific way shown below, but I'm unsure how.
Here's the relevant code:
// Object that can hold a copy of every type I want to print.
// Stores the copy in a union, with an enumeration to identify
// the type. any uses C++ constructors, but could also be implemented
// with C99 designated initializers, like so: https://ideone.com/ElQgBV
struct any
{
...
}
// The string format function requires the variable arguments
// to all be of the 'any' type for type safety and (essential for
// my purposes) positional printing.
// Arguments are accessed with a va_list, so essentially
// the variable arguments are treated as an array of any objects.
char* format_function_(const char* fmt, ...);
// I call the above function with this macro that expands the
// variable arguments and adds a default-constructed sentinel
// at the end. The sentinel is used by the function to count
// how many arguments were passed.
#define format(fmt, ...) format_function_(fmt, __VA_ARGS__, any())
// Calling the function like so, via the above macro...
char* str = format("bits:%4b string:%1 %0 int:%3h float:%2.2\n",
any("world"), any("hello"), any(3.14159f), any(42), any((u8)(1<<4)));
// ...returns this string:
// bits:00010000 string:hello world int:0000002A float:3.14
I'd like to be able to call the function like regular *printf style functions...
char* str = format("bits:%4b string:%1 %0 int:%3h float:%2.2\n",
"world", "hello", 3.14159f, 42, (u8)(1<<4));
...with the use of the any object hidden away, possibly behind another macro.
How can I accomplish this?
Edit/Update The positional arguments are essential for my purposes. Any answer that does not preserve this functionality is not a valid answer.
Since the C++11 standard there's something called parameter packs which makes this very simple:
char* format_function(const char* fmt, ...)
{
...
}
template<typename ...T>
char* format(const char* fmt, T... values)
{
return format_function(fmt, any(values)...);
}
...
char* str = format("bits:%4b string:%1 %0 int:%3h float:%2.2\n",
"world", "hello", 3.14159f, 42, (u8)(1<<4));
Maybe you'ld like something like this? (Alert: C++11 code!)
#include <stdio.h>
inline void format() {}
void format(char ch) {
fputc(ch, stdout);
}
void format(int i) {
if(i < 0) {
fputc('-', stdout);
i = -i;
}
int divider = 1;
while(i / divider >= 10)
divider *= 10;
do {
int digit = i / divider;
i -= divider * digit;
divider /= 10;
fputc('0' + digit, stdout);
} while(divider > 0);
}
void format(const char *str) {
fputs(str, stdout);
}
// TODO: Add more 'format()' overloads here!
template<typename FirstArg, typename... OtherArgs>
inline void format(const FirstArg &first, OtherArgs... others) {
format(first);
format(others...);
}
Then, you can simply...
const char *glorifiedIndex(int index) {
switch(index % 10) {
case 1:
return "st";
case 2:
return "nd";
case 3:
return "rd";
default:
return "th";
}
}
int main(int argc, const char *const argv[]) {
format("Hello, world!\n");
format("My name is ", argv[0], ", and I was given ", argc - 1, " argument", argc != 2 ? "s" : "", ".\n\n");
for(int i = 1; i < argc; i++)
format(i, glorifiedIndex(i), " argument: \"", argv[i], "\"\n");
format("Goodbye, world!\n");
}
This is a more flexible and elegant model, for the following reasons:
Semantically safe.
Type safe.
No <cstdarg> stuff.
No any stuff.
No incredibly badly-designed iostream stuff.
It's too simple to implemet, and I mean too much :). Compare this few lines of code with a typical 3000+ lines long printf.c. The difference is in several orders of magnitude!
You may have nostalgic moments relating with Java and Python.
If you change the type of any expression for whatever reason (i.e, int to unsigned), the function accomodates itself to this.
(Both good and evil) compiler optimizations can kick in easily.
The user of the library may extended the abilities of the format() function by means of overloading it with user-defined types.
This imposibilites the use of dynamic formats (this is intended for obvious security reasons).
This forces you to create special functions for what I call bit-printing, i.e, printing in a machine-parsable way, rather than human-readable as format() did, does, and will do.
You may use overloading features to extend this list yourself :).
I have two functions with a little different functionality, so I can't make them as template functions.
int func64(__int64 a) {
return (int) a/2;
}
int func32(int a) {
return a--;
}
Depending on variable b64, I would like to call func64 or func32. I don't want check if b64 is true many times in my code, so I use pointers to functions.
void do_func(bool b64) {
typedef int (*pfunc32)(int);
typedef int (*pfunc64)(__int64);
pfunc32 call_func;
if (b64)
call_func = func64; //error C2440: '=' : cannot convert from 'int (__cdecl *)(__int64)' to 'pfunc32'
else
call_func = func32;
//...
call_func(6);
}
How can I avoid this error and cast call_func to pfunc32 or pfunc64?
The language requires all functions called through the same function pointer to have the same prototype.
Depending on what you want to achieve, you could use the pointer/cast aproach already mentioned (which satisfies this requirement at the loss of type safety) or pass a union instead:
union u32_64
{
__int64 i64;
int i32;
};
int func64(union u32_64 a) {
return (int) a.i64/2;
}
int func32(union u32_64 a) {
return --a.i32;
}
void do_func(bool b64) {
typedef int (*pfunc)(union u32_64);
pfunc call_func;
if (b64)
call_func = func64;
else
call_func = func32;
//...
union u32_64 u = { .i64 = 6 };
call_func(u);
}
Pass a void pointer and cast it in the function body.
Of course this means less compiler control if you use the wrong type; if you call func64 and pass an int to it the program will compile and produce wrong results without giving you any tip of what is going wrong.
int func64(void *a) {
__int64 b = *((__int64*) a);
return (int) b/2;
}
int func32(void *a) {
int b = *((int *) a)
return b-1;
}
I need to call func32() or func64() depending on flag b64
So do that:
void do_func(bool b64) {
if (b64)
func64(6);
else
func32(6);
}
Well, first of all, please note that function func32 is returning the input argument as is.
This is because with return a--, you are returning the value of a before decrementing it.
Perhaps you meant to return a-1 instead?
In any case, you can simply declare this function as int func32(__int64 a).
This way, it will have the same prototype as function func64, but will work exactly as before.
BTW, calling a function through a pointer might be more "expensive" than a simple branch operation, so depending on your application, you might be better off with a simple if/else conditional statement...
Make a wrapper for func64:
int func64_as_32(int a) {
return func64(a);
}
Now you can assign either func32 or func64_as_32 to call_func since they have the same signature. The value you pass in, 6, has type int so passing it to func64_as_32 has the same effect as passing it directly to func64.
If you have call sites where you pass in a value of type __int64 then you'd do it the other way around, wrap func32.
As bool in C++ converts to int ( true => 1, false => 0 ) you can use b64 as array index. So take SJuan76's advice, convert your functions prototype to int f(void*) and put them into array int (*array_fun[2])(void* x); . You can call these functions then like that :
int p = 6;
array_fun[b64](&p);
Is the following possible in c++?
int do_stuff(int one, int two)
{
...
return ...;
}
int main()
{
void *ptr = &do_stuff(6, 7);//DON'T CALL THE FUNCTION, just store a pointer
cout << *ptr;//call the function from the pointer without having to pass the arguments again
}
I know this can be done with classes, but is it possible the way I am trying to do it?
Well with c++11 and a little magic from std::function and std::bind you can.
std::function<int()> f = std::bind(&do_stuff,6,7);
std::cout << f();
No, not like that. There is nothing in the code
void *ptr = &do_stuff(6, 7);
that makes it parse like you want. I'm unsure if it would parse at all, if you can take the address of the return value. Taking the address of a function is basically a no-op, but function pointers don't convert to void * so it has problems anyway.
You need more magic, like C++11's lambda closures.
I'm no C++11 programmer, but I guess your code would look like:
int main(void)
{
auto func = [] () { do_stuff(6, 7); };
func();
return 0;
}
I'm trying to learn c++ from the basics, and I was playing around with function pointers. Considering this code:
#include <iostream>
#include <string>
#include <vector>
bool print(std::string);
bool print(std::string a)
{
std::cout << a << std::endl;
return true;
}
bool call_user_function(bool(std::string), std::vector<std::string>);
bool call_user_function(bool(*p)(std::string), std::vector<std::string> args) {
if (args.size() == 0)
return (*p)(); (*)
else if (args.size() == 1)
return (*p)(args[0]);
else if (args.size() == 2)
return (*p)(args[0], args[1]); (**)
}
int main(int argc, char** argv)
{
std::vector<std::string> a;
a[0] = "test";
call_user_function(print, a);
// ok
return 0;
}
It gives me:
main.cpp:28 (*): error: too few arguments to function
main.cpp:32 (**): error: too many arguments to function
What am I doing wrong?
p is of type bool(*)(std::string). This means it is a pointer to a function that has a single parameter of type std::string and returns a bool.
p can point to print, because the type of print matches: it is a function that has a single parameter of type std::string and returns a bool.
Your first erroneous expression, (*p)(), attempts to call p with no arguments. Your second erroneous expression, (*p)(args[0], args[1]) attempts to call p with two arguments.
The number of arguments must match the number of parameters, so both of these are ill-formed, just like an attempt to call print directly with no arguments or with two arguments would result in a compilation error.
#JamesMcNellis has already addressed the problem with the code.
To make something like this work, you probably want to do something like:
bool call_user_function(bool(*p)(std::string), std::vector<std::string> args) {
bool ret = true;
for (int i=0; i<args.size(); i++)
ret &= p(args[i]);
return ret;
}
...or, you could use std::for_each (and since you're not using it anyway, I'll ignore the return value for the moment):
// avoid copying vector by passing reference to const vector.
void call_user_function(bool (*p)(std::string), std::vector<std::string> const &args) {
std::for_each(args.begin(), args.end(), p);
}
...but, since you're just printing out the contents of the vector, what you should probably use is something more like this:
std::copy(a.begin(), a.end(),
std::ostream_iterator<std::string>(std::cout, "\n"));
Also note that your a[0] = "test"; is invalid. You want a.push_back("test"); instead.
print has no overload for a call with no arguments.
print also doesn't have an overload for two std::string arguments.
I'm sure this has been asked before, but it's just hard to search for...
So, what I've got is a function that accepts a function pointer. This function pointer has, say, 3 arguments. So, I want to pass to another function, the same pointer, but with 2 arguments filled in.
So, something like this:
int func1 (int (*funcptr)(int, int, int)) {
return func2(funcptr(,8,9));
}
int func2 (int (*funcptr)(int)) {
return (*funcptr)(2);
}
EDIT:
Ok so I got this now with the usage of a lambda
int func2(int (*funcptr2)(int)) {
return (*funcptr2)(2);
}
int func1(int (*funcptr1)(int, int, int)) {
return func2(
[funcptr1](int i)->int {
return (*funcptr1)(i,8,9);
}
);
}
But it's giving me
"cannot convert func1(int (*)(int, int, int))::<lambda(int)> to int (*)(int) for argument 1 to int func2(int (*)(int))"
This is called a lambda, and you can do it with newer C++ versions, std::bind, boost::bind or boost::function.
To answer your updated question, a lambda which captures variables (as your lambda does with funcptr1) cannot be converted to a function pointer. Intuitively this makes sense since your lambda must store this captured variable per lambda; whereas there is no way to do that with a function pointer.
The best solution is probably to take an argument of type std::function, which is a wrapper for any callable type:
int func2(std::function<int(int)> funcptr2) {
return funcptr2(2);
}
int func1(std::function<int(int,int,int)> funcptr1) {
return func2(
[funcptr1](int i)->int {
return funcptr1(i,8,9);
}
);
}
You can also use templates to make your functions work for any callable type:
template <typename F>
int func2(F funcptr2) {
return funcptr2(2);
}
template <typename F>
int func1(F funcptr1) {
return func2(
[funcptr1](int i)->int {
return funcptr1(i,8,9);
}
);
}
In C, you can't. You would have to pass the function pointer, and the two arguments.
In C++, you can use std::bind (or boost::bind in older versions) to achieve this.