Function pointers to templated functions - c++

Assume we have the following function definitions
int function_wrapper_dummy( lua_State* ) { }
template < typename F, F* f >
int function_wrapper( lua_State* L ) { }
And the following function
template < typename F >
void register_function( F f )
{
int (*lf) (lua_State *L) = function_wrapper_dummy; // line 1
int (*lf) (lua_State *L) = function_wrapper< F, f >; // line 2
}
Compiling the above code works for line 1, but doesn't compile for line 2.
Quite humorously, VS2012 tells us:
error C2440: 'initializing' : cannot convert from 'int (__cdecl *)(lua_State *)'
to 'int (__cdecl *)(lua_State *)'
While Clang 3.3 emits:
error: address of overloaded function
'function_wrapper' does not match required type 'int (lua_State *)'
...int (*lf) (lua_State *) = function_wrapper< F, f >;
I use templated function adresses in less complex situations, so I see that it can be done. I checked that lua_State is the same lua_State, I've checked the calling conventions, and I've checked for name shadowing. I've also spent 2 hours trying to google the solution, to no avail (no, this is not a member function problem, only freestanding functions involved).
What am I doing wrong?

Any template argument must be determined at compile time. In register_function, the value of function pointer f is not known until the function is invoked at runtime.

This code compiled fine, hadly i got one error "function_wrapper_dummy" must return a value. I don't think there is an error,with this code.

Related

Need to assign pointer to a function generated from a function template (Visual Studio 2015)

I have a function that takes following arguments as below -
int X::MainFun(Pfn, void*,int)
and Pfn is defined as
int (*Pfn) (int*, void*, int);
Now I have a function template as follows :
template <typename IntfType>
static int MasterOps(int * pRec, void* pSt, int pOffset ){
IntfType* IfObj = (IntfType*) (((MasterOpArgs*)pSt)->vIfObj);
if(IfObj->MasterOps(pRec, pSt, pOffset) == MIGINTF_SUCC) return 1;
else return 0;
}
Now I am calling function MainFun as -
MasterOpArgs margs;
Xobj->MainFun(MasterOps<MigT>, &margs,0 );
type MigT is a class defined earlier which implements a member MasterOps and MainFun() is actually a member function of some class.
Definition of template and call for MainFun() is happening in same file.
I assumed that call to MainFun would also cause instantiation of function template MasterOps with type MigT, but it seems I am wrong as I see following errors
error C2440: 'type cast': cannot convert from 'overloaded-function' to 'Pfn': note: None of the functions with this name in scope match the target type
error C2059: syntax error: ','

why cant I pass a reference as a function argument for std::async [duplicate]

This question already has answers here:
Passing arguments to std::async by reference fails
(3 answers)
Closed 2 years ago.
I have this code.
int TA11::AsyncRunP(Unit *unit,Function func)
{
return 0;
}
int TA11::AsyncRunR(Unit& unit, Function func)
{
return 0;
}
void TA11::RunFunc(Unit& unit, Function func)
{
assert(!unit.fut_.valid());
unit.fut_ = std::async(std::launch::async, &TA11::AsyncRunR, this, unit, func);
unit.fut_ = std::async(std::launch::async, &TA11::AsyncRunP, this, &unit, func);
}
VS2019 c++17 mode. (Function is a class enum)
the first std::async wont compile, second one is fine.
1>C:\work\pdp\mysim\mysim\Ta11Cassette.cpp(115,19): error C2672:
'std::async': no matching overloaded function found
1>C:\work\pdp\mysim\mysim\Ta11Cassette.cpp(115,79): error C2893:
Failed to specialize function template
'std::future<_Invoke_traits<void,decay<_Ty>::type,decay<_ArgTypes>::type...>::type> std::async(std::launch,_Fty &&,_ArgTypes &&...)' 1>C:\Program Files
(x86)\Microsoft Visual
Studio\2019\Community\VC\Tools\MSVC\14.25.28610\include\future(1481):
message : see declaration of 'std::async'
1>C:\work\pdp\mysim\mysim\Ta11Cassette.cpp(115,79): message : With the
following template arguments:
1>C:\work\pdp\mysim\mysim\Ta11Cassette.cpp(115,79): message :
'_Fty=int (__thiscall TA11::* )(TA11::Unit &,TA11::Function)'
1>C:\work\pdp\mysim\mysim\Ta11Cassette.cpp(115,79): message :
'_ArgTypes={TA11 *, TA11::Unit &, TA11::Function &}'
std::async passes the arguments to the callable by value (doesn't make perfect forwarding), hence you got the error because your callable only accepts reference.
You can use std::ref() to pass your var by reference.

How to pass binary function to template function C++

I want to pass the standardized C++ binary functions to a template function, but somehow I didn't get it to work.
The following is my attempt to do it:
template<template <typename> typename Pred,typename T, typename Iterator>
void iota_stepa(Iterator begin, Iterator end, T startofSequence_, T threadStep)
{
int currMaxThreads = startofSequence_;
bool first = true;
generate(begin, end, Pred<T>(currMaxThreads, threadStep) );
}
and testing it with:
vector<int> tempVect_(10, 0);
iota_stepa<std::plus>(begin(tempVect_),end(tempVect_),1,thread::hardware_concurrency());
gives me unfortunately the errors:
Severity Code Description Project File Line Suppression State
Error C2440 '<function-style-cast>': cannot convert from 'initializer list' to 'std::plus<int>'
Error C2672 'generate': no matching overloaded function found FractalCarpet
Error C2780 'void std::generate(_FwdIt,_FwdIt,_Fn0)': expects 3 arguments - 2 provided FractalCarpet
The console output looks like the following:
1> c:\users\mtunca\documents\esd\sps\fractalcarpet\main.cpp(55): note: see reference to function template instantiation 'void iota_stepa<std::plus,int,std::_Vector_iterator<std::_Vector_val<std::_Simple_types<float>>>>(Iterator,Iterator,T,T)' being compiled
1> with
1> [
1> Iterator=std::_Vector_iterator<std::_Vector_val<std::_Simple_types<float>>>,
1> T=int
1> ]
1>c:\users\mtunca\documents\esd\sps\fractalcarpet\main.cpp(34): error C2672: 'generate': no matching overloaded function found
1>c:\users\mtunca\documents\esd\sps\fractalcarpet\main.cpp(34): error C2780: 'void std::generate(_FwdIt,_FwdIt,_Fn0)': expects 3 arguments - 2 provided
1> c:\program files (x86)\microsoft visual studio 14.0\vc\include\algorithm(1532): note: see declaration of 'std::generate'
Could someone help me, how to solve this problem?
std::generate needs a generator, something that can be called like gen().
You could create one with a lambda, perhaps like this:
template<template <typename> class Pred, typename T, typename Iterator>
void iota_stepa(Iterator begin, Iterator end, T startofSequence_, T threadStep)
{
bool first = true;
T current;
auto gen = [&]() -> T
{
if(first) {
current = startofSequence_;
first = false;
} else {
current = Pred<T>() ( current, threadStep );
}
return current;
};
generate(begin, end, gen );
}
Pred<T>(currMaxThreads, threadStep) );
Pred<T> is a type. You need to construct an actual callable object:
Pred<T>()(currMaxThreads, threadStep) );
This however cannot be the last argument to std::generate. The latter requires a callable object with no arguments, presumably holding a state (otherwise a call to std::fill woud suffice). It is unclear how an arbitrary binary function could be adapted to fill this role.

brace initialized function pointer array: invalid conversion from 'void (*(*)())()' to 'void (*)()'

In my arduino sketch I need an array of function pointers with the signature void foo().
I'm using the ino command line utillity on linux (which uses avr-g++ under the hood).
However I'm getting a very strange error while defining the array.
error:
error: invalid conversion from ‘void (* (*)())()’ to ‘void (*)()’
in this piece of code
void (*mode_setup[])(void) = {
&show_time_setup,
&set_time_setup,
&set_alarm_setup,
&set_date_setup // <-- generates 3 identical error on this line
};
I don't understand what I'm doing wrong, since... int foo[] = { 1, 2, 3 }; ..is perfectly valid, and void (*foo)(void) is the syntax for function pointer.
what am I missing?
edit: NEVERMIND IM STUPID
the functions were not void foo(), but fptr foo() [fptr=function pointer typedef]
sincere appologies for wasting peoples time
I can reproduce your error message with this code
void (*foo())() {}
void (*arr[])(void) = { &foo };
So it looks like the signature of the function(s) is not what you think it is. An array to hold a pointer to foo would need to be declared like this:
void (*(*arr[])())(void) = {
&foo
};
If I were you, I'd consider typedefs...

Variadic template to proxy QtConcurrent::run functions

I was hoping to create a variadic template function which sits in front of the QtConcurrent::run functions that does some stuff and then passes the parameters on.
QtConcurrent::run is massively overloaded - check out qtconcurrentrun.h
Is it possible to create a variadic template function that I can call which will pass through to QtConcurrent::run ? This is what I have thus far:
template <typename returnT, typename... Args>
static auto Run(Args&&... args) -> QFuture<returnT>
{
// Do Stuff
// Now call through to start the task
QFuture<returnT> future = QtConcurrent::run(std::forward<Args>(args)...);
QFutureWatcher<void>* futureWatcher = new QFutureWatcher<void>(); //A QFutureWatcher<void> is special, see QFutureWatcher QT docs.
futureWatcher->setFuture(future);
QObject::connect(futureWatcher, &QFutureWatcher<void>::finished, [=]() {
// Do stuff
futureWatcher->deleteLater();
});
return future;
}
I'm struggling to work out how to deduce the return type, so I've got the returnT as a separate template param. This doesn't compile (VS2012 Nov CTP) when called with:
Tasking::TaskManager::Run<void>([&]() { while (stopTask == false); });
With the top couple error messages being:
1> error C2065: '<lambda_86e0f4508387a4d4f1dd8316ce3048ac>' : undeclared identifier
1> Implementation\TaskingTests\TaskManagerTests.cpp(31) : see reference to function template instantiation 'QFuture<void> Tasking::TaskManager::Run<void,TaskManagerTests::WaitsForTaskTest::<lambda_86e0f4508387a4d4f1dd8316ce3048ac>>(TaskManagerTests::WaitsForTaskTest::<lambda_86e0f4508387a4d4f1dd8316ce3048ac> &&)' being compiled
1>C:\tkbt\Launch2.0.0\ICDE\IceLibrary\Implementation\Tasking/TaskManager.hpp(108): error C2974: 'std::forward' : invalid template argument for '_Ty', type expected
1> C:\Program Files (x86)\Microsoft Visual Studio 11.0\VC\include\type_traits(1780) : see declaration of 'std::forward'
1> C:\Program Files (x86)\Microsoft Visual Studio 11.0\VC\include\type_traits(1774) : see declaration of 'std::forward'
1>C:\tkbt\Launch2.0.0\ICDE\IceLibrary\Implementation\Tasking/TaskManager.hpp(108): error C2780: 'QFuture<T> QtConcurrent::run(const Class *,T (__cdecl Class::* )(Param1,Param2,Param3,Param4,Param5) const,const Arg1 &,const Arg2 &,const Arg3 &,const Arg4 &,const Arg5 &)' : expects 7 arguments - 0 provided
1> c:\qt\qt5.0.2\5.0.2\msvc2012_64\include\qtconcurrent\qtconcurrentrun.h(333) : see declaration of 'QtConcurrent::run'
Any help much appreciated.
I guess that TaskManager.hpp(108) is the line where you call QtConcurrent::run.
What you are experiencing seems to be this MSVC bug. In short, variadic templates cannot forward lambdas in MSVC. You probably will have to use an oldscool functor in this case or provide nonvariadic overloads to support lambdas, maybe for the first few arguments. If I had to guess I'd think QtConcurrent::run's first argument has to be a function and the other arguments are its parameters, meaning you never get to call Run without arguments. You could rewrite your function template to have one fixed "normal" parameter for the function and the parameter pack for the function arguments.
For the return type deduction you might want to use decltype. Together that would look like this:
template <class F, class... Args>
static auto Run(F&& f, Args&&... args)
-> decltype(QtConcurrent::run(std::forward<F>(f), std::forward<Args>(args)...))
{
auto future = QtConcurrent::run(std::forward<F>(f), std::forward<Args>(args)...);
//I suppose this can not be a smart pointer?
auto futureWatcher = new QFutureWatcher<void>();
futureWatcher->setFuture(future);
QObject::connect(futureWatcher, &QFutureWatcher<void>::finished, [=]() {
// Do stuff
futureWatcher->deleteLater();
});
return future;
}
This way, the lambda would be passed to the normal template parameter F, wich should be ok for forwarding, i.e. the bug should not happen this way.
Update: If QtConcurrent::run does not give you the correct return type right away, you could go by using decltype on the function and its arguments:
static auto Run(F&& f, Args&&... args)
-> QtFuture<decltype(f(std::forward<Args>(args)...))>
Maybe you'll need to add some std::remove_reference and std::remove_const to the decltype to get the right future type.