I'm new to C++ and I'm learning about lambdas,functors and callables, and I know that there's a wrapper class, namely std::function that allows callables of different types to be stored and called (as long as the have the same call signature,or function type).
Now, I understand that you can have function with function type parameters that are really just function pointer parameters as in :
void fun(int,int*(int,int&));
which is nothing more than a function that takes an int and a function pointer to a function like int *f(int,int&),even if the language allows me to pass a function as an argument (with or without the ampersand).Infact, the function parameter list might as well be written as:
void fun(int,int*(*)(int,int&));
Now,back to the std::function type
I know that I can instantiate std::function with a function type and that allows any kind of callable to be passed to the wrapper. But, a function type is not a type I can use as a template type argument in any instantiation such as:
std::vector<int(int)> f_vec;
instead, I should make a vector of function pointers
std::vector<int(*)(int)> f_vec;
and that would allow me to insert pointers to function,but not functors or lambdas.
So, my question is, how can I instantiate a template with a type argument like a function type?? what's happening under the hood in the library std::function type.I mean a function type seems to me a type I cannot use in templates?? pleas can you make things a little clearer,as I'm just beginning to learn these topics. Thanks
The reason why you cannot write std::vector<int(int)> is not something fundamental about using function types as template parameters. That's perfectly valid. It's just what std::vector<T> does with the T (like operate on it by value) which makes std::vector<int(int)> illegal.
This can be shown by using std::vector<int(int)> in a context where nothing bad happens, such as this:
typedef std::vector<int(int)> StillOk;
StillOk *p = nullptr;
As long as the template doesn't actually try to do anything illegal with int(int), it's fine.
So, as long as your template deals with its template parameter in a way which is legal for function types, you can use it with function types. Here's a hypothetical example:
template <class T>
struct MyPointer
{
T *p;
T& operator* () const { return *p; }
};
It's now perfectly legal to instantiate MyPointer<int(int)> and use its operator *, because it will only ever involve expressions of type int (*)(int) and int (&)(int). [Live example]
And that's pretty much also what std::function<T> does with its T—only things which are legal with a function type.
Related
I was wondering if writing anything resembling this declaration (making use of the parameter pack) is possible.
decltype(auto) (*funcPtr)(...);
If possible, I would also like to know about alternative ways to declare such a pointer.
C++ is a statically typed language. All function argument types and return types must be known at compile time. You cannot declare a function that returns arbitrary types (well, I guess you could return std::any, but I can't think of a case where you'd want to).
You can use templates, however, to create function templates where the compiler will stamp out multiple versions of a function for you, so you don't have to write them all yourself.
Remember that auto and decltype(auto) is not magic. They are just syntactic sugar for what you'd otherwise write yourself if they didn't exist. They do not enable any new features that weren't already in the language. They just make such features easier to use.
No, there is no type such as pointer to function "that returns anything". There are only pointers to a function that returns some type or void. auto merely deduces the type from an initialiser, and there is nothing to deduce the type from in your example.
You can however have a function template where the instance of the template is a function that returns a type specified by a template argument:
// function template
template<class T>
T foo() {
return {};
}
Likewise, you can have a variable template that is a pointer to function whose return type is specified by a template variable:
// variable template
template<class T>
T (*funcPtr)() = foo;
// example usage
int main() {
return funcPtr<int>();
}
Let us suppose that we have a function of n variables
y = f (x1, ..., xn)
Such a function I would like to pass as an argument.
In Matlab the following construction using a handle is available:
function y=func(x)
y = sin(x(0)) * cos(x(1)) //Any definition, not important
p_func=#func; //Define handle
It is possible to use the handle as a parameter of another function:
y = function2(p_func, n);
where n represents a dimension...
How to rewrite this code using C++? We use a simple model with the function template
temmplate <typename T>
T func( const T *arg, const short n) {return sin(arg[0]) * cos(arg[1])};
where xi arguments are represented by the 1-dimensional array of n elements. The problem is that in this case it is not possible to use a pointer to the function template
template <class T>
static T ( *pfunc ) ( const T *arg, const short n )
only a specialization... Perhaps another model could be more appropriate...Thanks for your help...
Remark:
I know that a class template is useful
template <typename T>
class Foo
{
T func( const T *args, const short n);
};
and this construction works:
template <class T>
static T ( *pfunc ) ( const T *arg, const short n )
But it may not be used in the current model of the library (I can not affect this).
C++ is a statically typed language. Every object in C++, whether a function pointer, or whatever, must have a specific type. And the type of a function pointer is based on the types of arguments that the function to be pointed to is given.
A template is not an object, so you can't get a pointer to one. You can get a pointer to an instantiation of a template. Using your func definition, func<int> is a function that takes a const int* and a short. You can get a pointer to func<int>. But func is a template; you can't get a pointer to a template.
That's why C++ programs often throw functors around instead of function pointers. Functors can have a template operator() method, so you can call them as though you were passing around template functions. But since you say that you have to use a function pointer, there's not much that can be done.
The problem is not the "n". The problem is the templated type T.
Are you trying to declare a variable (of type pointer to function), here?
template <class T>
static T ( *pfunc ) ( const T *arg, const short n )
This will not work without instantiating the template.
This is because of otherwise, type checking would be impossible. The type checker could not check if, when you initialized the pointer, T was the same as when you dereference it.
You will probably need to look at a bigger context. Where do you want to USE that declaration? Move the template parameter to that context.
For example, you could have a function, or class with template parameter T.
There, you could declare, initialize and dereference any function pointer which has T somewhere in it's type.
Maybe you can "bind" the parameters at the place where you assign the function pointer. So the resulting function will be a nullary function, which you can use without knowing the parameter types.
You cannot obtain pointer to template function, because template is not an object, it's just compile-time syntax construction producing multiple specific functions - template instantiations. Template instantiations, e.g. f<int>(const int*, short) are objects and can be pointed.
If you just want some simple and unified way to obtain function pointer from template instantiation, use declspec() (I'm supposing you are using modern C++11 compatible compiler):
template <class T> static T f(const T *, const short )
{
// Implementation
...
}
// Declaring function pointers for int & double
typedef decltype(&f<int>) IntFuncPtr;
typedef decltype(&f<double>) DoubleFuncPtr;
// Sample usage
IntFuncPtr intFunc = &f<int>;
intFunc(NULL, 0);
DoubleFuncPtr doubleFunc = &f<double>;
doubleFunc(NULL, 0);
I don't think this is easily solved in C++, but there are approaches for similar cases. You should take a look at the boost::bind and boost::function library. It was made for getting around the nasty details of passing function pointers around in C++ (and they allow to pass for class methods as well). As far as i recall they don't really use a generic N but instantiate templates for arbitrary N parameters. It's definitely worth a look if you want to get to something similar.
I remember that when using Boost.Spirit and for the std::function addition to C++0x, you specify the function type by using a syntax that doesn't use pointers, like in defining std::function<bool(int)> fn, whereas you would cast a pointer like (bool(*)(int))fn.
Can anyone tell me the name of this new syntax or any references on this, or how to use it? It seems like a polymorphic function type syntax that applies for functors as well, but I don't really know how to use it.
bool(int) is the type of the function; bool(*)(int) is the type of the function pointer. In other words, if you define
typedef bool(BF)(int);
typedef bool(pBF*)(int);
then BF* is the same as pBF.
The std::function template captures the return and argument types via (variadic) templates:
template <typename R, typename ...Args> struct function
{
function(R(&f)(Args...)); // conceptually
}
It is not new sintax, although old compilers did sometimes reject it. It is simply the type of a function versus the type of a function pointer, similar to the type of an arrays versus the pointer to an array.
The facts that there are no function l-values and that function r-values decay quickly to pointer-to-functions make them mostly useless. Except in the case of templates, of course.
Without knowing a function's type, I am declaring its pointer with below technique and initializing a function pointer.
template<typename T>
struct Declare { typedef T Type; }; // for declaring any func ptr
void fun () {}
int main ()
{
Declare<fun>::Type pf = &fun; // can't use C++0x 'auto'
}
However, it gives compile error as, error: expected a type, got ‘fun’. Though the type of any method is known at compile time. Is it invalid to pass a function into a class template as above ?
[Note: replacing fun with void (*)() works fine. But that's not what want.]
Is it invalid to pass a function into a class template as above ?
Totally yes, you're mixing up type and non-type parameters.
fun is a non-type argument, it's an address of a function, like an arbitary number 0x12345678.
typename T is a type parameter. You can only pass it types, like int,MyClass, double (*)(std::string), void (MyClass::*)().
You'll just have to life with the fact, that you need compiler support for that stuff or some really ugly trickery to deduce the type.
If you're in for the trickery, there's Boost.Typeof for non-C++0x coder like you. It also provides a stand-in for auto with BOOST_AUTO, but that is only a short way for writing BOOST_TYPEOF:
int hello(){ return 42; }
BOOST_AUTO(var1,hello()); // type of var1 == int
BOOST_TYPEOF(hello()) var2 = hello(); // same
The problem? You need to help it for every user-defined type you have. See this Ideone example.
Now, most of the time I don't think you need Boost.Typeof. Why? Because if you use a function, you of course need to know the signature, how would you pass the correct arguments otherwise? Or use the return type in a correct way?
The other times are the usage in templates anyways. If you declare a function pointer like auto fptr = &func, then you have the knowledge, that func exists, aka you know its signature and type. For when you don't know that func exists, you need it passed to you anyways, preferably in a template:
template<class FPtr>
void myfunc(FPtr otherfunc){
// use otherfunc
}
And with a template you have the knowledge of that functions type again.
Is it invalid to pass a function into a class template as above?
Yes. Because what you, in other words, want the compiler to deduce the type parameter for the class template, which simply not possible in C++. Recall that fun itself isn't a type, its a value of type void (*)(). But your class template expects type, not value. That's why it wouldn't work.
Type deduction is possible with functions only, that means even with the constructor of class. So if you write a templated constructor, and then you can write this:
Declare obj(&fun);
Here the type of the function is known as long as you're in constructor, once you exist from it, you lost the information. So what you probably need is : define a class, say, AbstractFunctor (possibly class template) and derived from it defining an another class say template<Fun fun> struct Functor. Then you can create an instance of Functor which can remember the function type forever, and store the instance in AbstractFunctor* as a member data of Declare.
But I think, even in this way, the type cannot be used as Declare::Type or Declare::AbstractFunctor::Type, simply because the type is stored in an instance of the class; only the instance knows the type. So the getting type using syntax like A::Type is out of the question. And you cannot get type using syntax instance.Type either. All you can do is : call the function, using the instance, like a functor.
EDIT:
If you're allowed to use C++0x's other features (excluding auto), then the problem has a trivial solution:
Declare<decltype(&fun)>::Type pf = &fun;
pf(); //call the function
Demo : http://ideone.com/
But then, you don't need even Declare, as you can do this instead:
decltype(&fun) pf = &fun;
pf(); //call the function
I have some questions concerning function templates.
My plan was to build a wrapper which derives from a user-defined class and
not only exports the public functions of that class but also its constructors.
So I decided I would use multiple constructor templates (which I presume work exactly
the same as function templates) with 1 to n parameters to satisfy most constructors needs.
These would than simply call the constructor and do something else afterwards, like
this:
template <class T>
class Wrapper : public T
{
public:
template <class U>
Wrapper(U &u) : T(u) { doSomething(); }
template <class U, class V>
Wrapper(U &u, V &v) : T(u,v) { doSomething(); }
...
};
My intent is to register the instance within the Wrapper-Ctor somewhere else and,
from that point on, it can receive calls to virtual functions defined in T.
I had to use the reference operator in the code above, in order to guarantee that
my Wrapper-Ctor does not have any side-effects on the parameters that were passed
(copy-construction).
To my surprise this always worked, except for temporaries, which is the reason why
I am confused about the types that are inferred by the compiler in this situation.
To simplify the situation I tried to do something similiar via a template function:
template <class T>
void foo(T &t)
{
int x = ""; // intentional error
}
Calling the function like this:
std::string a;
std::string &b = a;
foo(b);
To my surprise the compiler denotes [T = std::string] in its error message.
I would have expected for this to be [T = std::string&], which would have caused
passing a reference-to-reference, which is invalid.
So, why does the compiler deduce a value-type in this situation?
Is it even possible to create a Wrapper-Ctor that does what I want, does not
have any side-effects on the parameters and also accepts temporaries?
Thanks alot!
It looks like the C++ spec explicitly states that this is the intended behavior. Specifically, if you have a template function that takes in a parameter P that depends on a template type argument, if P is a reference, then the underlying type of the reference, rather than the reference type, is used to determine what type should be used for P (see §14.8.2.1/2). Moreover, this same section says that const and volatile qualifiers are ignored during this step, so the constness can be inferred automatically.
It is not possible in C++03 to provide such a thing without manually overloading for every combination of const and non-const parameters.
No expression ever has reference type. Therefor, when argument deduction deduces against the argument expression type, it cannot make a distinction between a and b because the arguments a and b both have the same type.
Refer to [expr]p5 in the spec
If an expression initially has the type "reference to T" (8.3.2, 8.5.3), the type is adjusted to T prior to any further analysis.
Somewhat late, but since I don't think this was answered completely...
For template parameter deduction, see the previous answers.
For your problem with temporaries, make the parameters const references (as in Wrapper(const U&)).
The thing is, temporaries are rvalues. The standard states that non-const references can only be bound to lvalues. Therefore, a standards compliant compiler won't let you pass temporaries(rvalues) as arguments to non-const reference parameters. (This doesn't have anything to do with templates in particular, it's a general rule).
This is to the best of my knowledge, so take it with a bit of scepticism.