std::function argument to receives any number of arguments - c++

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

Related

How can I pass a function name and variadic list of arguments to a function in C++?

Not a duplicate of What is std::invoke in c++?. That quesiton asks specifically about that one and only feature. This question asks about a concept which can be 100% solved withOUT that feature, and has multiple, alternative solutions, only some of which even use that feature.
In Python you can pass a function name and arguments list to an outer function, which calls the inner function and passes those args to it, like this:
Passing functions with arguments to another function in Python?:
def perform(fun, *args):
fun(*args)
def action1(args):
# something
def action2(args):
# something
perform(action1)
perform(action2, p)
perform(action3, p, r)
How do I do this in C++?
Like this:
template <typename F, typename ...P>
void foo(F &&func, P &&... args)
{
std::invoke(std::forward<F>(func), std::forward<P>(args)...);
}
If the function is called more than once, only the last call is allowed to use std::forward. The other calls have to be just std::invoke(func, args...).
You can get rid of std::invoke and use std::forward<F>(func)(std::forward<P>(args)...) and func(args...) respectively, but by doing this you lose support for member pointers as "functions".
To return the result of the function call, just do return std::invoke(...), and set the return type to decltype(auto) or std::invoke_result_t<F, P...>.
This works even when passing a function returning void.
If you want to make this SFINAE-friendly, you can use std::invocable:
template <typename F, typename ...P>
void foo(F &&func, P &&... args) requires std::invocable<F, P...>
{
std::invoke(std::forward<F>(func), std::forward<P>(args)...);
}
If the function is also invoked without forward, add && std::invocable<F &, P &...>.
To get the correct exception specification, add noexcept(std::is_nothrow_invocable_v<F, P...>) (and if the function is also invoked without forward, also check with <F &, P &...>).
How to use variadic templates (parameter packs) in C++ to pass a variadic list of arguments to a sub-function
Although you can do this in both C and C++ using variadic functions with va_list, va_start(), va_arg(), and va_end(), it is much cleaner and easier to do it in C++ using variadic templates (parameter packs) instead.
The secret is to allow a generic function to be passed in, of any format, via typename FuncType, and to allow a variadic list of arguments to be passed in via typename... FuncArgs. The template specifier will therefore be template<typename FuncType, typename... FuncArgs>. You then pass the function name to the outer function as FuncType innerFunc, and you pass the list of variadic arguments to the outer function as FuncArgs... args. Inside the template function, the list of arguments can then be passed to a subfunction as args..., like this: innerFunc(args...);.
Here is the whole thing in context:
// INNER FUNCTIONS TO PASS TO AN OUTER FUNCTION
void print1(int i)
{
printf("print1: %i\n", i);
}
void print2(double d, int i)
{
printf("print2: %f, %i\n", d, i);
}
void print3(int i, double d, const std::string& str)
{
printf("print3: %i, %f, %s\n", i, d, str.c_str());
}
// OUTER FUNCTION
template<typename FuncType, typename... FuncArgs>
void OuterFunc(FuncType innerFunc, FuncArgs... args)
{
printf("OuterFunc start.\n");
// Call the inner function with all passed-in args!
printf("Calling inner function with all passed-in args.\n");
innerFunc(args...);
printf("OuterFunc end.\n\n");
}
int main()
{
OuterFunc(print1, 100);
OuterFunc(print2, 99.1234, 77);
OuterFunc(print3, 123, 10.55, "hey you!");
return 0;
}
Full, runnable example, with comments:
variadic_templates_parameter_packs_and_functions.cpp from my eRCaGuy_hello_world repo:
// C++ includes
#include <cstdint> // For `uint8_t`, `int8_t`, etc.
#include <cstdio> // For `printf()`
#include <iostream> // For `std::cin`, `std::cout`, `std::endl`, etc.
#include <string>
// -------------------- Some inner functions to choose from START -------------------
void print1(int i)
{
printf("print1: %i\n", i);
}
void print2(double d, int i)
{
printf("print2: %f, %i\n", d, i);
}
void print3(int i, double d, const std::string& str)
{
printf("print3: %i, %f, %s\n", i, d, str.c_str());
}
// -------------------- Some inner functions to choose from END ---------------------
// The outer function, which is a variadic template, containing one `typename...` parameter pack.
// See: https://en.cppreference.com/w/cpp/language/parameter_pack
template<typename FuncType, typename... FuncArgs>
void OuterFunc(FuncType innerFunc, FuncArgs... args)
{
printf("OuterFunc start.\n");
// Call the inner function with all passed-in args!
printf("Calling inner function with all passed-in args.\n");
// See the "Expansion loci" section of this documentation here:
// https://en.cppreference.com/w/cpp/language/parameter_pack
// This is really cool, because calling the inner function like this is **just like the Python
// example here!**: https://stackoverflow.com/a/803632/4561887--except you pass the arguments
// to the inner function as `args...` in C++ here instead of as `*args` (the contents of the
// arguments list) in Python.
innerFunc(args...);
printf("OuterFunc end.\n\n");
}
// int main(int argc, char *argv[]) // alternative prototype
int main()
{
printf("Demonstrate variadic templates (parameter packs) in C++!\n\n");
OuterFunc(print1, 100);
OuterFunc(print2, 99.1234, 77);
OuterFunc(print3, 123, 10.55, "hey you!");
return 0;
}
Sample build and run command, and output:
eRCaGuy_hello_world/cpp$ time g++ -Wall -Wextra -Werror -O3 -std=c++17 variadic_templates_parameter_packs_and_functions.cpp -o bin/a && bin/a
real 0m0.281s
user 0m0.245s
sys 0m0.036s
Demonstrate variadic templates (parameter packs) in C++!
OuterFunc start.
Calling inner function with all passed-in args.
print1: 100
OuterFunc end.
OuterFunc start.
Calling inner function with all passed-in args.
print2: 99.123400, 77
OuterFunc end.
OuterFunc start.
Calling inner function with all passed-in args.
print3: 123, 10.550000, hey you!
OuterFunc end.
References
Multiple typename arguments in c++ template? (variadic templates)
cppreference.com: variadic templates (parameter packs)
I think we can create template class to pass function pointer. Here is my example to call both free function and class method.
template<typename T>
class Invoker;
template<class C, typename Ret, typename... Args>
class Invoker<Ret (C::*)(Args...)>
{
public:
Ret Invoke(Ret(C::*method)(Args...), C* instance, Args... args) {
return std::invoke(method, instance, std::forward<Args>(args)...);
}
};
template<typename Ret, typename... Args>
class Invoker<Ret(Args...)>
{
public:
Ret Invoke(Ret(method)(Args...), Args... args) {
return std::invoke(method, std::forward<Args>(args)...);
}
};
// use
void foo(int a) {
cout << __FUNCTION__ << a << endl;
}
int bar() {
cout << __FUNCTION__ << endl;
return 42;
}
class Foo {
public:
void foo(int a) {
cout << __FUNCTION__ << a << endl;
}
};
int main()
{
Foo f;
Invoker<decltype(&Foo::foo)> inv;
inv.Invoke(&Foo::foo, &f, 10);
Invoker<decltype(foo)> inv2;
inv2.Invoke(&foo, 5);
Invoker<decltype(bar)> inv3;
inv3.Invoke(&bar);
return 0;
}

Template variadic function in template class won't compile

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;
}

pass lambda to function that accepts function with templated types

I'm attempting to make a template function that takes a function as a parameter and the parameter function has arguments for the template to deduce.
Example time:
Here is a function that accepts a fixed function type and works
void func_a(void(*func)(int)) {
func(1);
}
int main() {
auto f = [](int x) -> void { printf("%i\n", x); };
func_a(f);
return 0;
}
Here is what I want to do, expanding on the first example (this won't compile)
template <typename... T>
void func_b(void(*func)(T...)) {
func(1);
}
int main() {
auto f = [](int x) -> void { printf("%i\n", x); };
func_b(f); // neither of
func_b<int>(f); // these work
return 0;
}
Ideally I'd like func_b to accept both a regular function and a lambda function like func_a does, but with template magics.
Unfortunately, template deduction doesn't work well with implicit conversions. However, you can convert the lambda explicitly into a function pointer type. The shortest, but somewhat confusing way to do that is to apply unary + operator:
func_b(+f);
Or you could use the more intuitive, but also verbose and DRY-violating cast operation:
func_b(static_cast<void(*)(int)>(f));
But perhaps, you'll want to simply accept any callable type, instead of only function pointers:
template <class Fun>
void func_c(Fun&& func) {
func(1);
}
This works fine with lambdas. No conversions involved.
func_c(f);
And it also works for capturing lambdas (that cannot be converted to function pointers), std::function and function objects such as those defined in <functional>.
here you have some options that work:
#include <functional>
template <typename T>
void func_b(T&& func) {
func(1);
}
template <typename... T>
void func_c(std::function<void(T...)> func) {
func(1);
}
template <typename... T>
void func_d1(std::function<void(T...)> func) {
func(1);
}
template<typename... Params>
using fun = std::function<void(Params...)>;
template <typename T, typename... P>
void func_d(T& func) {
func_d1(fun<P...>(func));
}
int main() {
auto f = [](int x) { printf("%i\n", x); };
func_b(f);
func_b(std::function<void(int)>(f));
func_c(std::function<void(int)>(f));
func_d<decltype(f),int>(f);
return 0;
}
The issue is: A lambda is not a function pointer or std::function-object.
func_b uses perfect forwarding so T will be the type of the lambda not a std::function object.
For func_c. You should not convert a lambda to a c-style function pointer. A std::function object is able to do this conversion but only explicitly (by design) so you need to explicitly convert them.
func_d (and func_d1) combine the other aspects. It forwards the lambda and makes a std::function-object explicitly out of it though it needs an additional template parameter.

Removing excess parameter pack parameters with minimal overhead

I want to make a function object that allows me to bind a function that has less parameters than the function object.
So for example:
int SomeFunction(int i) { return i * i; }
Function<int, int, float> function(&SomeFunction);
Calling function(5, 3.14f); would call the function with 5 as the parameter, and 3.14f would simply be ignored.
The goal is to create something similar to Qt's signal and slot mechanism in standard C++.
What kind of template magic can I use to achieve this?
You may use std::tuple and std::function:
template<typename Ret, typename... Ts>
class Function{
public:
template<typename...Us>
Function(Ret(*f)(Us...)) : Function(std::index_sequence_for<Us...>{}, f) {}
template <typename ... Us>
Ret call(Us&&... args)
{
return mF(std::forward<Us>(args)...);
}
private:
template<std::size_t... Is, typename...Us>
Function(std::index_sequence<Is...>, Ret(*f)(Us...))
{
mF = [f](Ts... args)
{
return f(std::get<Is>(std::forward_as_tuple(args...))...);
};
}
private:
std::function<Ret(Ts...)> mF;
};
Live Demo

How to bind variadic template params to function

I'm trying to mimic std::thread constructor functionality:
template< class Function, class... Args >
explicit thread( Function&& f, Args&&... args );
I've tried stepping with debugger to see how it works but I couldn't figure it out.
How can I create and store bind type like thread's constructor does ?
Something like this (the syntax maybe wrong):
class myClass{
private:
auto bindType;
public:
template< class Function, class... Args >
explicit myClass( Function&& f, Args&&... args ) : bindType(somehowBind(f, args) {}
void evaluate() {bindType();}
};
Example of usage:
int test(int i) {return i;}
int main(){
myClass my(test, 5);
my.evaluate();
}
Note that I don't care if somehowBind function will ignore the return type i.e. its return type can be something like std::function.
All I wan't to do is understand how I can bind class... Args to a given function f such that after calling somehowBind it will act like std::bind does.
To clarify my point you can think about what I'm trying to achieve as follow:
thread t(test, 5); // unlike the usual std:::thread, this one is created in suspended mode therefore I need somehow to bind `f` with `5` and store it
t.start(); // now t is executed
It's kinda reminds C# and Java threads, they not executed right after construction.
For starters, to bind some parameters to a function using std::bind you simpy do:
// Some function.
void printValues(int x, double y) {
std::cout << x << " " << y << std::endl;
}
auto func = std::bind(printValues, 5, 2.0); // Bind params and return functor.
func(); // Evaluate function call (returns void in this case).
Next, to store a functor and its parameters in a class and you don't care about the return value when evaluating then simply use a lambda expression to wrap the std::bind expression (the lambda is used to drop the return value):
struct Foo {
template <typename Function, typename... Args>
Foo(Function&& func, Args&&... args) {
auto f = std::bind(std::forward<Function>(func), std::forward<Args>(args)...);
func_ = [f] { f(); };
// func_ = [f{std::move(f)}] { f(); }; // In C++14 you can move capture.
}
void evaluate() { func_(); }
std::function<void()> func_;
};
Also see this live example
If you're looking to store a variadic pack then see this answer: How to store variadic template arguments?