How do I apply just the template arguments to a function that expects template arguments, without implicitly also calling the function with zero arguments? I want a function or delegate pointer instead of a value.
void foo(T)(double x) {}
auto bar() {
return foo!(int);
}
hack.d(36): Error: function hack.foo!int.foo(double x) is not callable using argument types ()
hack.d(36): missing argument for parameter #1: double x
If you had an ordinary function
void foo() {}
and you wanted a function pointer to it, how would you do that?
&foo
Now, suppose you have a template:
void foo(T)() {}
and want a pointer to a specific instance... you can probably guess at this point :)
&foo!arg
Related
I'm sorry if this is a very noobish question, but I'm confused on how you can specify std::function argument lists like this:
std::function<void(double)> func;
But in an actual function, this doesn't work:
void passFunc(void(double) func) {}
For the method above you have to specify a function pointer. So how is void(double) allowed to be passed into std::function? Is void(double) even a type? If not, how can it be in the argument list for std::function? If it is a type, why is it not valid to have void(double) be the type of a function parameter?
You can declare a type like that:
using Func = void(double);
But in the definition, you still need the name of the argument; otherwise, you could not use it in the function:
void passFunc(void func(double)) {}
Note that func is inbetween the return type and the arguments. If you don't like that, you can use the above-defined type:
void passFunc(Func func) {}
In C/C++ there are two ways to declare a function that returns nothing.
First one is to declare a function without arguments:
// no arguments
void f() {
}
The second one is to declare a function that takes void:
// still no arguments
void f(void) {
}
However, this is not true for the function result: we can't omit void at the beginning of the function like this:
// returns nothing
f() {
return; // yay
}
So, is there absolutely no way to omit void at the beginning of the function like with the function arguments?
So, is there absolutely no way to omit void at the beginning of the function like with the function arguments?
No, there absolutely isn't. There is no function declaration syntax that doesn't have the return type in C++ nor in C99 or later. There used in C prior to C99, but the default return type would have been int rather than void.
Note that declarations void f() and void f(void) are not equivalent in C. Former declares a function with unspecified parameters while the latter declares a function with empty parameter list. In C++, both declare a function with empty parameter list.
I am a bit puzzled with the following behavior. I pass a function with two parameter, one having a default value, as a template parameter and call the function with one argument. Why does it fail to compile? And, what is the solution/workaround?
#include <iostream>
using namespace std;
template<typename Function>
void eval(Function function) {
function(10);
}
void sum(int i, int j = 0) {
cout << "Sum is " << i + j;
}
int main() {
sum(10); // OK, of course :)
eval(sum); // Error!
}
Note that this question is not about calling a templated function with default parameter.
The error message:
prog.cpp: In instantiation of 'void eval(Function) [with Function = void (*)(int, int)]':
prog.cpp:15:10: required from here
prog.cpp:6:10: error: too few arguments to function
function(10);
^
That's because the optional parameter is part of function declaration. When you call using a function pointer, essentially all the compiler knows is the type of the function pointer. So this line function(10) roughly translates to:
void (*)(int, int) sm = function; // the equivalent happens at the type deduction step
sm(10); // whoops, where is the second int
The compiler will need the second argument because it has no way of knowing whether sm is pointing to sum which has a default argument, or some other void foo(int a, int b) which doesn't have a default argument.
This is why function pointers are weak. You got two good answers of why this doesn't work - the function template doesn't know your function has a defaulted argument.
The solution is to not pass a function pointer - pass in a function object. In this case, you can handwrite a lambda:
eval([](int i){ return sum(i); });
which seems like a really annoyingly verbose way of basically just writing sum in a way that actually works. But this sort of thing comes up periodically (what if sum were an overloaded name?) so it's handy to just have a lambdafying macro around (C++14 required):
#define AS_LAMBDA(func) [&](auto&&... args) -> decltype(auto) { \
return func(std::forward<decltype(args)>(args)...); }
so you can write:
eval(AS_LAMBDA(sum));
That will work with defaulted arguments, overloaded names, and even work to bind member functions:
struct X {
int i;
int add(int j) { return i + j; }
};
X x{42};
eval(AS_LAMBDA(x.add));
When you call sum:
sum(10);
compiler translates it to:
sum(10, 0);
There is no error, as arguments are matched. For the compiler there exist no sum taking one argument. You can say a pre-compiler doing the magic of passing 0 to second argument to sum. With templates this magical pre-compiler doesn't exist, and the actual compiler matches sum with two strictly two arguments, which it doesn't find, and hence the error.
Just like
void foo(int);
void foo(float);
will fail to compile with foo(10.2); where argument double can be changed to either float or int. The compiler will not assume float for you. Similarly, compiler will not try to find best match of sum just for the sake of successful compilation.
I'm find out a bit confusing thing in C code
struct SomeStruct {
// ...
void (*f)(const void *x);
};
void do_some( void f(const void *x) ) { // what?
struct SomeStruct* v;
// ...
v->f = f;
}
As I can understand do_some take function instead function pointer.
But what is difference with void do_some( void (*f)(const void *x) ) in practice? When I should use this? Is this allowed in C++?
There is no difference. It's just syntactic sugar. It is allowed in both C and C++.
Function parameters are simply rewritten by the compiler as function pointer parameters, just as array parameters are rewritten by the compiler as pointer parameters.
For reference, here is an excerpt from the C standard, section 3.7.1:
g(int (*funcp)(void))
// ...
or, equivalently,
g(int func(void))
As I can understand do_some take function instead function pointer.
No, as a function parameter a function type is adjusted to the corresponding function pointer type. The argument f has the same function pointer type as the member f.
But what is difference with void do_some( void (*f)(const void *x) ) in practice?
None whatsoever.
When I should use this?
If you like extra verbosity. Or in other contexts, such as declarations, where you need to distinguish function and pointer types.
Is this allowed in C++?
For function parameters (and also non-type template parameters) the same adjustment is applied in C++.
Can i actually use a function overloading like this:
#include <iostream>
void foo(...)
{
std::cout << "::foo(...) \n";
}
void foo(int)
{
std::cout << "::foo(int) \n";
}
int main()
{
foo(0);
foo('A');
foo("str");
foo(0, 1);
}
What standard says about it? And in what kind of situations i'll get ::foo(...)?
void foo(int)
will accept one argument of type int.
void foo(...)
accepts any number of arguments, of any type. It will be selected when the call doesn't have a single int argument. Not very useful, in general.
Also note that it is undefined behavior to pass objects of class type to ....
In N3337 I can see:-
13.3.2 Viable functions
A candidate function having fewer than m parameters is viable only if
it has an ellipsis in its parameter list (8.3.5). For the purposes of
overload resolution, any argument for which there is no corresponding
parameter is considered to “match the ellipsis” (13.3.3.1.3) .
When you declare a function in the following way :
void foo (...)
this mean foo accepts any number of arguments.
So this function will be called when this is the must suitable one.
In your case whenever you won't write :
foo(//Some single int).
In your specific main, this will happen :
foo(0) //Calls foo(int).
foo('A) //Calls foo (int). as you can convert a char to an int.
foo("str") //Calls foo(...) . as you can not convert a string to an int.
foo(1,2) //Calls foo(...) . as this is the only possible function
cause the second foo function only takes one int.
void foo(...) will take variable arguments. And it will be called when there the no or type of argument does not match the provided argument list of other function with the same function name.
foo(0); //This will call void foo(int) function
foo('A'); //This will call void foo(int) function
foo("str"); //This will call void foo(...) function
foo(0, 1); //This will call void foo(...) function
NOTE:
Although the ellipsis works fine with function overloading, it is not highly recommend pursuing variadic functions. At least not until you have significantly more experience in C++ to understand the pitfalls. I would suggest its use only with the try catch block where there are situations when the error cannot be predicted.