I'm trying to write a function for a template class which takes in a parameter that is a function pointer for a member class inside the private data of the big class. When you call that member, it calls that function on smaller class. (Confusing right?) To demonstrate, I have a non-working example here:
#include <vector>
#include <iostream>
using namespace std;
template <typename T, typename C>
struct MyClass {
template <typename F, typename... A>
auto call_me(F func, A... args) { // pass in the function we want to call
return (mContainer.*func) (args...); // call the function supplied by
// the parameter on the private member data
}
C mContainer; // this will be private in my actual code
};
int main() {
MyClass<int, std::vector<int> > test;;
cout << test.call_me(&std::vector<int>::size) << endl; // works
test.call_me(&std::vector<int>::insert, test.mContainer.begin(), 4); // doesn't work
return 0;
}
Please note that this isn't my actual code but a small example of what I'm trying to do. As you can see, I'm trying to call the size member function of the 'Private' (I have kept it public here for demonstration) vector class inside MyClass. This only works whenever I have no parameters for the compiler to unpack, but when I try to do the insert function (which has parameters to unpack), the compiler gives me an error of:
.\template.cpp: In function 'int main()':
.\template.cpp:24:71: error: no matching function for call to 'MyClass<int, std::vector<int> >::call_me(<unresolved overloaded function type>, std::vector<int>::iterator, int)'
test.call_me(&std::vector<int>::insert, test.mContainer.begin(), 4);
^
.\template.cpp:10:10: note: candidate: template<class F, class ... A> auto MyClass<T, C>::call_me(F, A ...) [with F = F; A = {A ...}; T = int; C = std::vector<int>]
auto call_me(F func, A... args) { // pass in the function we want to call
^~~~~~~
.\template.cpp:10:10: note: template argument deduction/substitution failed:
.\template.cpp:24:71: note: couldn't deduce template parameter 'F'
test.call_me(&std::vector<int>::insert, test.mContainer.begin(), 4);
This is the same error I'm getting in my actual production code, calling the variadic function with no parameters to unpack works, but if I give more than that, I get the same error message. This is my first real attempt to use Variadic templates, so any recommendation and help will be appreciated.
The problem here is that insert is an overloaded function. The compiler is not doing to try and resolve what overload you want in template argument deduction as there is no way for it to know. You have to cast the function to the type of the overload you want to use in order to give it a type. That would look like
using insert_func_t = std::vector<int>::iterator(std::vector<int>::*)(std::vector<int>::const_iterator, const int&);
test.call_me(static_cast<insert_func_t>(&std::vector<int>::insert), test.mContainer.begin(), 4);
In general it is
static_cast<return_type(class_name::*)(function_parameters)>(&class_name::function_name)
Another option would be to change the function a little and take a lambda that expresses what you want done. That would look like
template <typename T, typename C>
struct MyClass {
template <typename F, typename... A>
auto call_me(F func, A... args) { // pass in the function we want to call
return func(mContainer, args...); // call the function supplied by
// the parameter on the private member data
}
C mContainer; // this will be private in my actual code
};
int main() {
MyClass<int, std::vector<int> > test;;
test.call_me([](auto& container, auto... args){ container.insert(args...); }, test.mContainer.begin(), 4);
return 0;
}
Basically you cannot take address of an unresolved overloaded function, because the compiler won't be able to choose the right function entry point address. During normal function call the compiler resolves overloaded function, but with templates like yours or std::bind() this won't work, because the parameters are used to call the template function, not the function you want to take address of.
You can manually resolve the overload like this:
using ftype = std::vector<int>::iterator(std::vector<int>::*)
(std::vector<int>::const_iterator, const std::vector<int>::value_type&);
test.call_me((ftype)(&std::vector<int>::insert), test.mContainer.begin(), 4); // works
It's easier to deal in function objects when doing this kind of thing. It offloads the problem of method overloads to the compiler.
Lambdas also work (they're function objects):
#include <vector>
#include <iostream>
template <typename T, typename C>
struct MyClass {
template <typename F, typename... A>
auto call_me(F func, A&&... args) -> decltype(auto)
{ // pass in the function we want to call
return func(mContainer, std::forward<A>(args)...); // call the function supplied by
// the parameter on the private member data
}
C mContainer; // this will be private in my actual code
};
/*
* It's often easier to deal in function objects
*/
struct insert
{
template<class Container, class...Args>
decltype(auto) operator()(Container& cont, Args&&...args) const
{
return cont.insert(std::forward<Args>(args)...);
}
};
struct size
{
template<class Container, class...Args>
decltype(auto) operator()(Container& cont) const
{
return cont.size();
}
};
int main() {
MyClass<int, std::vector<int> > test;;
std::cout << test.call_me(size()) << std::endl; // works
test.call_me(insert(), test.mContainer.begin(), 4); // doesn't work
// or lambdas
auto insert2 = [](auto& container, auto&&...args) -> decltype(auto)
{
return container.insert(std::forward<decltype(args)>(args)...);
};
test.call_me(insert2, test.mContainer.begin(), 5);
return 0;
}
Related
I've defined a template function that receives std::function. and I want to send a member function. that works fine (example: test2)
How can I rewrite it so std::function receives any number of argument? (test3)
another question - can this be done without the std::bind?
struct Cls
{
int foo() { return 11; }
};
template<typename T>
void test2(std::function<T()> func)
{}
template<typename T, typename... Args>
void test3(std::function<T(Args... args)> func, Args&&... args)
{}
int main()
{
Cls ccc;
test2<int>(std::bind(&Cls::foo, ccc)); // Ok
test3<int>(std::bind(&Cls::foo, ccc)); // does not compile!
}
This is the error I receive:
no matching function for call to ‘test3<int>(std::_Bind_helper<false, int (Cls::*)(), Cls&>::type)’ 34 | test3<int>(std::bind(&Cls::foo, ccc));
The issue is that std::bind doesn't return a std::function, it returns some unspecified callable type. Therefore the compiler can't deduce the correct template parameters for test3.
The way to work around that is to make your function accept any callable type instead of trying to accept a std::function:
template <typename Func, typename... Args>
void test3(Func&& func, Args&&... args)
{}
This will work with a std::bind result, a lambda, a raw function pointer, a std::function, etc.
can this be done without the std::bind?
Sort of. A pointer to a member function always requires an instance of the class to be called on. You can avoid needing to explicitly std::bind the instance into a wrapper by passing it as a parameter and using the std::invoke helper to call the function. For pointers to member functions, std::invoke treats the first parameter as the object to call the member on.
For example:
struct Cls
{
int foo() { return 11; }
};
template <typename Func, typename... Args>
void test3(Func&& func, Args&&... args)
{
std::invoke(std::forward<Func>(func), std::forward<Args>(args)...);
}
void bar(double, int) {}
int main()
{
Cls ccc;
test3(bar, 3.14, 42); // Works with a raw function pointer
test3(&Cls::foo, ccc); // Works with a pointer to member function
test3([](int){}, 42); // Works with other callable types, like a lambda
}
Demo
can this be done without the std::bind?
Yes this can be done without std::bind as shown below.
struct Cls
{
int foo() { return 11; }
int func(int, double)
{
return 4;
}
};
template<typename className, typename... Param,typename Ret, typename... Args>
void test4(Ret (className::*ptrFunc)(Param... param),className& Object, Args... args)
{
(Object.*ptrFunc)(args...);
//std::invoke(ptrFunc, Object, args...); //WITH C++17
}
int main()
{
Cls ccc;
test4(&Cls::foo, ccc); //works
test4(&Cls::func, ccc, 4,5); //works
}
Working demo
With C++17 we can use std::invoke to replace the call (Object.*ptrFunc)(args...); with:
std::invoke(ptrFunc, Object, args...); //WITH C++17
C++17 std::invoke demo
template<class Fn, class ...Args>
class func_class<Fn(Args...)> // Do not know what to do here
{
typedef typename result_of<Fn(Args...)>::type mytype;
std::function<mytype(Args...)> func_;
std::tuple<Args...> tuple1;
public:
func_class(Fn&& func_in, Args&& ...args)
{
func_ = func_in;
tuple1 = make_tuple(args...);
}
mytype
exe ()
{
mytype ret;
ret = apply(func_, tuple1);
return ret;
}
};
int func(int a) {return a;}
int main () {
// return type of "func" can be deduced by "result_of<decltype(func)&(int)>::type"
// And result_of is declared as "result_of<Fn(Args...)>"
// Want func_class to have the same interface
func_class<decltype(func)&(int)> fc; // Want to declare a object like this
fc.exe();
}
The code is like above. Return type of func can be deduced by result_of<decltype(func)&(int)>::type. And result_of is declared as result_of<Fn(Args...)>.
Want func_class to have the same interface as result_of.
The compiler complains like:
test.cpp:211:7: error: 'func_class' is not a class template
What can I do?
Thank you in advance.
template<class Sig>
struct bob;
template<class R, class...Args>
struct bob<R(Args...)>{
//...
};
specialization.
Uses of bob that fail to pattern match will give compile-time errors.
As a note, using R(Args...) syntax when R is not a return value and Args... are not arguments will lead to unexpected quirks, because of how function argument and return value types are modified by the C/C++ language.
This is why std::result_of<F(Args...)> is deprecated and replaced with std::invoke_result<F, Args...>.
R(Args...) is appropriately used in std::function, because Args... are function arguments, and R is an actual return value, to function<A(Args...)>::operator().
I try to pass to a variadic template function a list of references and pass it to another function. The code that I wrote is the following:
template <typename T>
void fun(cv::Point_<T> & pt) { pt.x++; pt.y++; }
template <class ... args>
void caller(args & ... list) {
typedef typename std::tuple_element<0, std::tuple<args...> >::type T;
std::array<std::reference_wrapper<T>, sizeof...(list)> values {list ... };
for(int i=0; i<values.size(); i++)
fun(values[i]);
}
then I call the function caller in this way:
cv::Point2f a, b, c;
caller(a, b, c);
the compiler give me the following error:
No matching function for call to 'fun'
Candidate template ignored: could not match 'Point_' against 'reference_wrapper'
what I missing?
Although std::reference_wrapper<T> has an implicit conversion to T&, you cannot use both an implicit conversion and template argument deduction at the same time, and template argument deduction is necessary to call fun.
Try
fun(values[i].get());
Even simpler is
template <typename...Args>
void caller(Args&...args)
{
auto tmp = { (func(args),0)..., 0 };
}
This uses the fact that parameter pack expansion can occur in braced init lists. Since func() returns void, we cannot simply use { func(args)... }, but use (func(args),0) to have an int. Finally, the last 0 is to ensure that the code compiles (and does nothing) in case of an empty parameter pack.
You can generalise this and write a template that calls a given generic function for every element of a pack:
template <typename Func, typename...Args>
void call_for_each(Func &&func, Args&&...args)
{
auto unused = { (func(std::forward<Args>(args)),0)...,0 };
}
which may be used like this (C++14)
int main()
{
int a=1;
double b=2.4;
auto func = [](auto&x) { std::cout<<' '<<x++; };
call_for_each(func,a,b);
std::cout<<'\n';
call_for_each(func,a,b);
std::cout<<'\n';
}
This uses a C++14 lambda (taking an auto argument). Note that the parameter pack must come last among the template parameters of call_for_each.
Since the goal of this might be to iterate over all args, here's a more generic solution. We are going to implement for_pack:
template<typename... Args, typename F>
void for_pack(F function, Args&&... args) {
using expand = int[];
(void)expand{(function(std::forward<Args>(args)), void(), 0)..., 0};
}
This will execute function for every args in Args.
Now, your function caller is much more trivial to implement:
template <typename... args>
void caller(args&... list) {
for_pack([&](cv::Point_<T>& arg){
fun(arg);
}, list...);
}
Since a google search for "c++ pass reference parameters to variadic template" gives this as first result, I'll put this generic solution here.
struct HH { /*...*/ void change_me() { /*...*/ } };
template<typename...T> void parms_r_refs() {}
template<typename H, typename...T> void parms_r_refs(H &h, T&...t) { h.change_me(); parms_r_refs(t...); }
template<typename...T> void parms_r_refs(T&...t) { parms_r_refs(t...); }
HH a, b, c;
..
parms_r_refs(a, b, c);
..
I'm trying to implement a function template (in C++11) whose parameter is a lambda with arbitrary parameters, and return a compatible std::function object. The goal is for the returned function when called to invoke the original lambda asynchronously, but for now I'm just returning the original lambda.
The problem is simply getting the compiler to accept a lambda as the parameter of the function template. Here are some simple templates:
#include <functional>
using namespace std;
template <class Arg>
function<void(Arg)> pass1(function<void(Arg)> fn) {
return fn;
}
template <class... Args>
function<void(Args...)> passn(function<void(Args...)> fn) {
return fn;
}
They do the same thing, it's just that pass1 only works on single-parameter functors while passn takes an arbitrary number.
So now we try using them, first pass1:
auto p1 = pass1( [](int a)->void {cout << a;} ); // ERROR
This doesn't work; the compiler can't seem to tell what parameters the lambda takes. Clang error message is:
Untitled.cpp:17:12: error: no matching function for call to 'pass1'
auto p1 = pass1( [](int a)->void {cout << a;} );
^~~~~
Untitled.cpp:6:21: note: candidate template ignored: could not match 'function<void (type-parameter-0-0)>' against '(lambda at Untitled.cpp:17:19)'
function<void(Arg)> pass1(function<void(Arg)> fn) {
I can work around this by explicitly specifying the template parameter type:
auto p2 = pass1<int>( [](int a)->void {cout << a;} ); // OK
However, this workaround fails with passn:
auto p3 = passn<int>( [](int a)->void {cout << a;} );
Untitled.cpp:23:12: error: no matching function for call to 'passn'
auto p3 = passn<int>( [](int a)->void {cout << a;} );
^~~~~~~~~~
Untitled.cpp:11:25: note: candidate template ignored: could not match 'function<void (int, type-parameter-0-0...)>' against '(lambda at Untitled.cpp:23:24)'
function<void(Args...)> passn(function<void(Args...)> fn) {
^
The weird thing is that I can invoke passn if I pass it a function object:
function<void(int)> fn = [](int a)->void {cout << a;};
auto x = passn<int>(fn); // OK
...in fact, I don't even have to specify the template parameter type:
auto y = passn(fn); // OK
The function I actually need is going to be like passn, but I don't want the extra verbiage of having to wrap a function object around the lambda every time I call it. Am I missing something, or is this just not possible? Would it be possible in C++14?
You can use this implementation of passn:
#include <functional>
#include <iostream>
template <class RetVal, class T, class... Args>
std::function<RetVal(Args...)> get_fun_type(RetVal (T::*)(Args...) const);
template <class RetVal, class T, class... Args>
std::function<RetVal(Args...)> get_fun_type(RetVal (T::*)(Args...));
template <class T>
auto passn(T t) -> decltype(get_fun_type(&T::operator())) {
return t;
}
int main() {
auto fun = passn([](int a) { std::cout << a; });
fun(42);
}
(demo)
It assumes you pass in a type that has an operator(). It takes the address of that function and deduces parameters from that member pointer.
The function will fail if you pass it an object that has multiple operator()s because then taking its address will be ambiguous, but lambdas will not produce that problem.
I would like to create template class which could store function pointer and arguments for a this function so the function can be later invoked with this arguments.
I would like to write this universally and not to depend on argument types or number.
Here is a scatch of the idea with the use of variadic templates of c++11:
template<class T, typename... Params>
class LazyEvaluation {
private:
// Function to be invoked later
T (*f)(Params...);
// Params for function f
Params... storedParams; // This line is not compilable!
bool evaluated;
T result;
public:
// Constructor remembers function pointer and parameters
LazyEvaluation(T (*f)(Params...),Params... params)
: f(f),
storedParams(params) //this line also cannot be compiled
{}
// Method which can be called later to evaluate stored function with stored arguments
operator T&() {
// if not evaluated then evaluate
if (! evaluated) {
result = f(storedParams...);
evaluated = true;
}
return result;
}
}
I would like to have at least the public interface of this class type safe if it is possible. Although getting this work at least somehow is more important.
I've managed to save the variable number of arguments somehow. But I wasn't able to pass them to the function f. I will write it to answers, but I would like you to think about your own solutions before you see my ugly not working attempt.
I am tring to compile the code above with Microsoft Visual C++ Compiler Nov 2012 CTP (v120_CTP_Nov2012), but it would be best if a compiler independent solution would exist.
Thank you
Here is how I tried to solve it:
The parametr pack can be recursivle expanded and each parametr saved. Function store is supposed to do it. It uses one (two times overloaded) helper function.
template<typename T>
void storeHelperFunction(void*& memory, T last) {
*((T*)memory) = last;
memory = (void*)((char*)memory + sizeof(T));
}
template<typename T, typename... Params>
void storeHelperFunction(void*& memory, T first, Params... rest) {
storeHelperFunction(memory, first);
storeHelperFunction(memory, rest...);
}
template<typename... Params>
void store(void* memory, Params... args) {
// Copy of pointer to memory was done when passing it to this function
storeHelperFunction(memory, args...);
}
Function store takes a pointer to memory where the varialbe number of arguments is supposed to be saved.
The pointer can point to some dynamicly allocated memory or beter to the structure which size is equal to sizeof...(Params).
Such structure which has exactly any desiared size can be constructed using template metaprogramming:
template <int N>
struct allocatorStruct {
char byte1;
allocatorStruct<N-1> next;
};
template <>
struct allocatorStruct<1> {};
I am not sure what the standart says or how the other compilers than the microsoft one compile it. But using my compiler the sizeof(allocatorStruct) is equal to N for any N which is greater or equal to 1.
Hence allocatorStruct<sizeof...(Params)> has the same size as Params.
Another way to create something which has the same size as Params is to use a type char [sizeof...(Params)]. This has the disadvantage that the compiler passes only pointer to this array when you try to pass such array as argument.
That is why it is better to use allocatorStruct<sizeof...(Params)>.
And now the main idea:
When saving the function we can cast it to: T (*)(allocatorStruct<sizeof...(Params)>).
When saving the arguments for the function we can save them to struct of the type allocatorStruct<sizeof...(Params)>.
The size of the arguments is the same. Although the function pointer lies about the type of the function the function pointed to will get its data correctly.
At least I hoped. Depending on the calling convention I expected that the passed arguments can be reordered or wrong because of the difference between left to right saving arguments and right to left passing. But it wasn't the case. Using __cdecl calling convention only first argument was passed and the other was lost. With other calling conventions the program stoped working.
I didn't spend much time debugging it and looking to data in memory(on stack). Is it at least right way to go?
Simply use a lambda expression
// Some function.
int add(int a, int b) {
return a + b;
}
auto lazyFunc = [] { return add(1, 2); };
std::cout << lazyFunc() << std::endl; // Evaluate function and output result.
If you really want to create a class that only evaluates the function once (lazily), using variadic templates, you could do something like in the following code.
I also made the class as such that you don't have to create a new instance every time the parameters change. I use a std::tuple to store the given arguments, and compare against previously given arguments. If the arguments differ, then the function will be reevaluated.
Functions are passed around and stored using a std::function wrapper so I don't have to work with raw function pointers (yuck).
#include <iostream>
#include <functional>
#include <utility>
#include <tuple>
template <typename T>
class LazyEvaluation {};
template <typename ReturnType, typename... Params>
class LazyEvaluation<ReturnType(Params...)> {
private:
std::function<ReturnType(Params...)> func_;
ReturnType result;
std::tuple<Params...> oldParams; // Contains the previous arguments.
public:
explicit LazyEvaluation(std::function<ReturnType(Params...)> func)
: func_(std::move(func)) {}
template <typename... Args>
ReturnType operator() (Args&&... args) {
auto newParams = std::make_tuple(std::forward<Args>(args)...);
// Check if new arguments.
if (newParams != oldParams) {
result = func_(std::forward<Args>(args)...);
oldParams = newParams;
std::cout << "Function evaluated" << std::endl;
}
std::cout << "Returned result" << std::endl;
return result;
}
};
int main() {
auto f = [] (int a, int b) {
return a + b;
};
// Specify function type as template parameter.
// E.g. ReturnType(Param1Type, Param2Type, ..., ParamNType)
LazyEvaluation<int(int, int)> ld(f);
std::cout << ld(1, 2) << std::endl;
std::cout << ld(1, 2) << std::endl;
std::cout << ld(3, 4) << std::endl;
}
Output:
Function evaluated
Returned result
3
Returned result
3
Function evaluated
Returned result
7
Given the standard machinery for forming variadic index packs:
template <std::size_t... I> struct index_sequence {};
template <std::size_t N, std::size_t... I>
struct make_index_sequence : public make_index_sequence<N-1, N-1, I...> {};
template <std::size_t... I>
struct make_index_sequence<0, I...> : public index_sequence<I...> {};
and to call functions with unpacked tuple arguments:
template <typename Function, typename... Types, std::size_t... I>
auto apply_(Function&& f, const std::tuple<Types...>& t, index_sequence<I...>)
-> decltype(std::forward<Function>(f)(std::get<I>(t)...)) {
return std::forward<Function>(f)(std::get<I>(t)...);
}
template <typename Function, typename... Types>
auto apply(Function&& f, const std::tuple<Types...>& t)
-> decltype(apply_(f, t, make_index_sequence<sizeof...(Types)>())) {
return apply_(f, t, make_index_sequence<sizeof...(Types)>());
}
This is fairly straightforward:
template<typename Function, typename... Params>
class LazyEvaluation {
private:
typedef decltype(std::declval<Function>()(std::declval<Params>()...)) result_type;
// Function to be invoked later
Function f;
// Params for function f
std::tuple<Params...> storedParams;
mutable bool evaluated;
union {
std::aligned_storage<sizeof(result_type)> space;
mutable result_type result;
};
// Method which can be called later to evaluate stored function with stored arguments
void evaluate() const {
// if not evaluated then evaluate
if (! evaluated) {
new (&result) result_type{apply(f, storedParams)};
evaluated = true;
}
}
public:
// Constructor remembers function pointer and parameters
LazyEvaluation(Function f, Params... params)
: f(std::move(f)),
storedParams(std::move(params)...),
evaluated(false)
{}
~LazyEvaluation() {
if (evaluated)
result.~result_type();
}
operator result_type&() {
evaluate();
return result;
}
operator const result_type& () const {
evaluate();
return result;
}
};
template <typename Function, typename... Params>
LazyEvaluation<Function, Params...>
make_lazy(Function&& f, Params&&... params) {
return {std::forward<Function>(f), std::forward<Params>(params)...};
}
I've used a union and placement new to store the result of evaluation so that it doesn't need to be a default-constructible type, and some mutable tricks so that a const LazyEvaluator can be converted as well as a non-const instance.