In the parameter's of a function, I want to pass a default argument that is a function template. What I'm trying to decipher is the difference between (*cmp) or (cmp) in the function below:
template <typename Type>
int Foo(some var, int (*cmp)(Type one, Type two) = FunctTemplate) { ...
I am used to seeing the * as a pointer declaration... Is this a pointer to the function FunctTemplate? Why does the program see to work regardless of way I write it (astrik or no astrik)?
The types are not the same, but there is no difference when they are used as a parameter type in a function declaration.
In int (*cmp)(Type, Type), cmp has pointer-to-function type (or a "function pointer" type).
In int (cmp)(Type, Type), cmp has function type (i.e., it is not a pointer type at all).
However, C and C++ both have a rule that any parameter that has a function type is implicitly converted to the corresponding function pointer type, just as any parameter that has an array type is implicitly converted to the corresponding pointer type.
Related
void(*)(void) is a function pointer while I suppose void(void) is also a way to represent function type. It is used as template parameter in std::function <functional>
What is void(void) and how it is different from void(*)(void)?
What is void(void) and how it is different from void(*)(void)?
They are distinct types. Although the former(void(void)) can be implicitly converted to the latter(void(*)(void)) in many contexts.
The type void(void) is called a function type. The following are also function types:
int (int, int) //this is a function type
void(int) //this is a function type as well
On the other hand, void (*)(void) is a pointer to a function type. That is, it is a pointer that points to a function with 0 parameters and return type of void.
TL;DR
The void(void) is a specification of a function type, it's
signature.
The void(*)(void) is a pointer to function.
These are distinct.
First, let's start by saying, that sometimes the void(void) will be automatically treated as a pointer to function (i.e. in a parameter list). We still can be explicit and use the void(*)(void), but the void(void) will be an equivalent in these cases.
// Here, we explicitly state that the f is a pointer to function
void foo(void (*f)(void), int i);
// Equivalent, f is automatically treated as a pointer to the function
void foo(void f(void), int i);
This will not be the case for the mentioned std::function for example. The types of the two are different, yet may have similar behavior (i.e. we can use the function call operator on a pointer to function).
void bar();
// Prints 1
std::cout << std::is_same<void(void), decltype(bar)>::value << '\n';
// Prints 1 as well
// Note the pointer type specifier
std::cout << std::is_same<void(*)(void), decltype(bar)*>::value << '\n';
// Prints 0
// Note the absence of the pointer type specifier
std::cout << std::is_same<void(*)(void), decltype(bar)>::value << '\n';
And particularly:
// Ok
std::function<decltype(bar)> fn1 = bar;
// error: variable ‘std::function<void (*)()> fn2’ has initializer but incomplete type
std::function<decltype(bar)*> fn2 = bar;
Note, that we can however "store" a pointer to a member function in std::function, but even then the template's parameter still won't be of a pointer to function type, but a plain function signature.
struct MyType {
void func(int) {}
};
int main() {
// Note, we can't have a member function without an instance of the type
// Thus we specify the usually implicit first param and the explicit int param
std::function<void(MyType&, int)> fn_mem = &MyType::func;
MyType my_object;
fn_mem(my_object, 21);
}
For more on std::function please refer to the reference. In short, the use of the std::function instead of the function pointers has the same moto as using the smart pointers instead of the raw pointers.
You may wonder on other uses of the void(void) or int(int) style function type specifications, so here's another example you may see often:
using func_t = int(int);
// func_ptr_func return a pointer to the func_t type alias
func_t* func_ptr_func();
N.B. unlike in the case of a parameter, the compiler won't treat the function type in a return as a pointer to function type. Thus, we must explicitly specify the pointer type in case of the return.
// Here, baz is a function that doesn't take any agruments
// And returns a pointer to a function that takes an int argument and "returns" void
void (*baz())(int);
for void fun(){}, std::is_same_v<void(void)>, decltype(fun)> is true; and std::is_same_v<void(*)(void)>, decltype(&fun)> is true. In fact, those are their real types. However, the standard approve you convert an object that has type void(void) to void(*)(void) implicitly (so you can even write (******funptr)()), that's why we always confuse them.
I saw this type here. I believe he's trying to create a variable pf for a member pointer type-erased (that's why there's void* there). I then noticed this type signature in similar such classes.
But according to isocpp a non-static member pointer type is defined like this:
int (Fred::*)(char,float) (for some class Fred)
and a function pointer type is defined like this:
int (*)(char,float)
Therefore one would create a member pointer variable mp like this:
int (S::*mp)(int) = nullptr;
Maybe this void* represents this* and its another way to define a member pointer variable by defining a function pointer variable? Is this possible?
What is R(*pf)(void*, Args...)?
It's the declaration of a function pointer. Nothing more than that.
Compatible functions take void* and Args..., and return R.
In the given example, the compatible function that's assigned to the pointer, is a lambda. The void* is the type-erased address of some callable f, and the Args... members are, well, the arguments that'll be passed to that callable. The callable's type is restored by capturing of type aliases inside the lambda (nice!).
R(*pf)(void*, Args...) is a function pointer (regular one, not pointer-to-member) to a function that returns R and has (void*, Args...) parameters, where Args... is a list of types (an expanded template parameter pack).
Maybe this void* represents this* and its another way to define a member pointer variable
Nah, there is no such feature in C++.
If you look at the code, the only things assigned to this pointer are lambdas, like this one:
pf = [](void* ptr, Args... args)->R{
return blah;
};
I'm not sure why you expected pointers-to-members to be involved.
I have seen this definition of a function that receives a function pointer as parameter:
double fin_diff(double f(double), double x, double h = 0.01) {
return (f(x+h)-f(x)) / h;
}
I am used to see this definition with an asterisk, i.e.:
double fin_diff(double (*f)(double), double x, double h = 0.01);
Do you know why the first definition is also valid?
Standard says that these two functions are equivalent as function arguments are adjusted to be a pointer to function arguments:
16.1 Overloadable declarations [over.load]
(3.3) Parameter declarations that differ only in that one is a function type and the other is a pointer to the same function type are equivalent. That is, the function type is adjusted to become a pointer to function type (11.3.5).
same in C:
6.7.5.3 Function declarators (including prototypes)
8 A declaration of a parameter as ‘‘function returning type’’ shall be adjusted to ‘‘pointer to
function returning type’’, as in 6.3.2.1.
Pointers to functions are peculiar. Given a function void f();, you can do
void (*fptr)() = f;
void (*fptr)() = &f;
void (*fptr)() = &&f;
void (*fptr)() = &&&f;
ad infinitum.
Similarly, when you call a function through a pointer to function you can do
fptr();
(*fptr)();
(**fptr)();
(***fptr)();
ad infinitum.
Everything collapses.
If a function parameter is specified as a function declaration then the compiler itself implicitly adjusts the parameter as a function pointer.
It is similar to when a function name is passed as an argument of some other function as for example
fin_diff( func_name, 10.0 );
the compiler again implicitly converts the function designator to a pointer to the function.
So I was taking a look through http://en.cppreference.com/w/cpp/types/result_of and saw the syntax for doing result_of of a member function and I just don't understand what is going on with that decltype.
Why do the args come after the decltype? Wouldn't they be important in figuring out the type of the member function? In my mind I imagine that instead of decltype(&C::Func)(C, char, int&) it should be decltype(&C::Func(C, char, int&)) or something of the like, but I'm having a hard time wrapping my head around it. Can anyone please explain why it is this syntax?
std::result_of takes a template argument of the form F(A...). F should be a type that is callable, such as a function type or a class type with an overloaded operator(). A... should be a sequence of argument types.
Therefore, if you have some expression e and some argument types A... and you want to know what result type you will get if you call e with arguments of types A... then you would put F = decltype(e) in std::result_of<F(A...)>, that is, std::result_of<decltype(e)(A...)>.
I'm copying the relevant code from the example that you pointed to:
#include <type_traits>
struct C {
double Func(char, int&);
};
int main()
{
// result_of can be used with a pointer to member function as follows
std::result_of<decltype(&C::Func)(C, char, int&)>::type g = 3.14;
static_assert(std::is_same<decltype(g), double>::value, "");
}
decltype(&C::Func) is the declared type of method Func of C, which is a function taking a C reference (corresponding to this), a char and an int reference.
Let us call this type T.
Then, result_of<T(...)>::type will be the type of the result of applying a function of type T to the arguments whose types you specify in the parentheses.
Therefore, in this example, result_of<decltype(&C::Func)(C, char, int&)>::type will be double.
As you are aware, the type T1(T2,T3) means a function returning a value of T1 and taking arguments of type T2 and T3. As soon as you are working with values of that type, you are bound to that interpretation.
std::result_of does not deal with any values, just with a type of the form T1(T2,T3), so it technically has the freedom to interpret the types any way it likes. And it actually does! If std::result_of would be parametrized over the type of a function, and return the return type of that function, the result (i.e. nested type member) would just be T1, but it isn't. The standard writers chose to implement a different functionality: std::result_of takes the type T1 in it's type parameter not to be the return type of the function to be determined, but the complete type of some callable thing (e.g. a function pointer), and it will return the type returned by that callable thing when passed the arguments T1 and T2.
Example time!
#include <iostream>
#include <ostream>
#include <type_traits>
#include <typeinfo>
int main(void)
{
// define the type of a function
typedef int ftype(char, long);
// (A) doesn't compile: you can't call an int
std::cout << typeid(std::result_of<int(char,long)>).name() << '\n';
// (B) doesn't compile: A the return type of a function may not be a function
std::cout << typeid(std::result_of<ftype(char,long)>::type).name() << '\n';
// (C) does compile and print the typeid name of int. On g++ this is "i"
std::cout << typeid(std::result_of<ftype*(char,long)>::type).name() << '\n';
}
Case (A) fails, as int is not callable, although the template parameter itself is well-formed. Case (B) fails, as the template parameter is not well-formed. In T1(T2,T3), T1 must not be a function type, as types describing a function returning a function are forbidden. Case (C) has a valid template parameter, in which the return type of the "function" describes a callable type, so std::result_of is applicable.
With this context in mind, the answer to your question is likely obvious. The expression decltype(&C::Func)(C, char, int&) describes a function type returning decltype(&C::Func) and taking the parameter types C, char and int &. As already discussed, the return type has to be something callable, which is the case for decltype(&C::Func), as it is the pointer-to-member-function type double (C::*)(char, int&). According to the definition of the INVOKE operation (see the page about callable), this type is callable with a parameter list (C, char, int&), so the application std::result_of to decltype(&C::Func)(C, char, int&) is valid.
The alternative you suggest: std::result_of<decltype(&C::Func(C, char, int&))> is not valid, as &C::Func(C, char, int&) is not a valid expression. If you want to constrain the type (in case there are multiple overloads of Func), you can do that using a cast, though. decltype(static_cast<double (C::*)(int, char&)>(&C::Func)) is a valid expression, returning (no surprise there) the type double (C::*)(int, char&). But like in example (A), this is not a type you may apply std::result_of on.
The really interesting use-case for std::result_of is the case in which T1, the callable type, is a function object. By passing the type of a function object to std::result_of as T1, you are passing all function-call operators of that object at the same time and you can have std::result_of pick the right one using overload resolution. Passing "all the Func functions" like you pass "all the operator() functions" is not possible, because std::result_of is hardwired to look for operator() in case of objects, and you can't use the address-of operator to map operator() invocations to Func() invocations. You can write a template doing this mapping, though:
#include <iostream>
#include <ostream>
#include <type_traits>
#include <typeinfo>
class S {
public:
int Func(int);
double Func(float, float);
};
template <typename T>
class call_Func : public T {
public:
template<typename... args>
auto operator()(args... vals) -> decltype(this->Func(vals...)) { return this->Func(vals...); }
};
int main(void)
{
std::cout << typeid(std::result_of<call_Func<S>(int)>::type).name() << '\n';
}
The template call_Func redirects calling operator() on call_Func<S> to calling Func on the base class S (one should use std::forward, though), but note you can not write a "generic redirector" that gets the name of the function to redirect the function call operator to as template parameter, as you can neither pass overload set nor names as template parameters, but just types and constant values (for non-type parameters). Pointer-to-member-functions are one kind of constant value, but you already lost the overloading as soon as you form such a pointer.
I'm used to seeing syntax like this for function pointers
int (*pointer_name) (float, char *);
void call_function (void (*)(int), int);
In some C++03 functional libraries I see types used this way:
abc::function<void(*)(int,float)> f;
In C++11's std::function I see the type given this way
std::function<void(int,float)> f;
There is a missing (*). Why?
The C++03 function<T> has T being an identical type to the corresponding function pointer. It's easy to imagine the implementation.
std::function in C++11 is supported by core language enhancements. Have template argument types been extended to accomodate callability?
std::function (and its inspiration, boost::function) does not only store function pointers. It can also store function objects. In that sense, passing a function signature as a template parameter is similar to how a smart pointer usually take the type of the pointee as a template parameter, not a pointer type!
Contrast:
int* p; // indirection to an object of type int
std::unique_ptr<int> q; // indirection to an object of type int
with
typedef void signature_type(); // a function type
// indirection to something callable with signature_type as a signature
// i.e. f() has type void
// only work for freestanding functions however
signature_type* f;
// indirection to something callable with signature_type as a signature
// i.e. g() has type void
// not restricted to function pointers!
std::function<signature_type> g;
This is a useful convention.
There is nothing magic here, the type
void(int,float)
is the type of a function without the names. It matches a function like void g(int x, float y).
With templates you don't have to use function pointers, you can use function types as well.
As with other elements, functions have a type, and you can use either the type or the pointer to the type in different contexts. The missing (*) you are expecting is just the pointer-to syntax.
int (*pointer_name) (float, char *);
typedef int my_function_type(float,char*);
my_function_type * pointer_name2;
The types of pointer_name and pointer_name2 are the same: pointer to a function that returns int and takes two arguments of types float and char*. Note that this is exactly equivalent to other types like int, with the difference that you cannot declare a variable to be of type function, only pointer to function.
The interface of std::function (or boost::function) just takes the signature of the function. The type argument is not a pointer to function but rather the type of a function (like my_function_type in the code above)
Function types aren't new in C++11 (see 8.3.5 in C++98). IIRC, the improvement over what TR1 and boost provide for function are quite minor.