I want to use variadic template feature for my application but I don't want the objects to be passed by value (as objects are quite complex in my case). I want to pass them by reference (not as pointers).
void func()
{
}
template<typename Function1, typename... FurtherFunctions>
void func(Function1 f1, FurtherFunctions... further_functions)
{
// doing some processing here...
}
How could I pass the arguments by reference and ensure that they are not copied?
Just say:
template <typename ...Args>
int myfunction(Args & ... args)
{
/* ... */
}
Same for const Args & ... args, Args && ... args etc.
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
In general, I have a poor idea of how to create such a type:
template<typename... Args>
using TWrapper = void *(*)(void *target, Args... func_args);
I understand why this is throwing errors, but I don't know what to do about it ...
I am developing a class with content something like this:
template<typename TFunc> //TFunc is a type of user's function
class CallManager {
TFunc user_function = nullptr;
void* inner_state; //For example
template<typename... Args>
using TWrapper = void *(CallManager::*)(void *const target, Args... func_args);
TWrapper wrapper_from_another_instance = nullptr; //What do I need to specify in the template arguments if I don't know them?
template <typename... Args> //I need to create a type for this function
void* WrapUserFunction(void *const target, Args&&... func_args) {
user_function(std::forward<Args>(func_args)...);
}
void setTargetExecutor(TWrapper wrapper) {
wrapper_from_another_instance = wrapper;
}
public:
void setFunction(TFunc func) {
user_function = func;
}
template <typename... Args>
void makeCall(Args&&... func_args) {
wrapper_from_another_instance(inner_state, std::forward<Args>(func_args)...);
}
void bindManager(const CallManager &next) { //Upd 1
setTargetExecutor(next.WrapUserFunction);
}
};
Using the example of the above class, it is possible to notice that I need an "extended" type in order to create a variable-pointer to a function for it, and then call it.
My class accepts a custom function type, but I don't know how many arguments there are and what type they are. Is it possible to somehow extract the list of arguments?
How can I create a type for a function starting with "template<typename... Args>"?
How can I supplement the user's type with my own argument to save the result in variable for call?
UPD 1: example of usage
using myfunc = void(*)(char x, char y);
void myFunc(char x, char y) {
}
void main() {
CallManager<myfunc> cmgr1;
cmgr1.setFunction(myFunc);
CallManager<myfunc> cmgr2;
cmgr2.bindManager(cmgr1);
cmgr2.makeCall(10, 15);
}
If you limit you class to take function pointer, you might do:
template<typename TFunc> //TFunc is a type of user's function
class CallManager;
template<typename R, typename... Args>
class CallManager<R (*)(Args...)>
{
using TFunc = R (*)(Args...);
using TWrapper = void *(CallManager::*)(void *const, Args...);
// ...
};
If you need to support more callable type, I suggest to create a "function_traits" in the same principe (template specialization) as helper.
Demo/Demo2
I have the following template function with specialization:
// Pass the argument through ...
template<typename T, typename U=T>
U convert(T&& t) {
return std::forward<T>(t);
}
// ... but convert std::strings
const char* convert(std::string s) {
return s.c_str();
}
If I then have a variadic template function like:
template<typename ... Args>
void doSomething(Args ... args) {
// Convert parameter pack using convert function above
// and call any other variadic templated function with
// the converted args.
}
Is there any way to convert the parameter pack using the convert function as in the comment?
My original goal was being to be able to pass std::string to '%s' in a printf like function without having to manually calling .c_str() on the strings first. But I am also interested in general if this can be done in a simple way, my tries so far failed.
template<typename ... Args>
void doSomething(Args ... args) {
something(convert(args)...);
}
Where something(convert(args)...) is a parameter pack expansion that expands to:
// pseudocode
something(convert(arg0), convert(arg1), convert(arg2), ...)
BTW, you might want to take args by forwarding references in order to avoid unnecessary copies and to properly propagate lvalue references:
template<typename... Args>
void doSomething(Args&& ... args) {
something(convert(std::forward<Args>(args))...);
}
template <typename Func, typename... Args>
static void WraperFunc(Func func, Args &&... args) {
SomeFunc(func, args...);
}
vs
template <typename Func, typename... Args>
static void WraperFunc(Func func, Args ... args) {
SomeFunc(func, args...);
}
Which is better and more recommended? Or is there an alternative which is better than both?
The Args && will accept lvalues, and rvalues by reference and enables them to be forwarded on maintaining their original value category. I would favour that version (and use std::forward).
template <typename Func, typename... Args>
static void WraperFunc(Func func, Args &&... args) {
SomeFunc(func, std::forward<Args>(args)...);
// ^^^^^^^^^^^^ Use of forward
}
Note the idiomatic use of std::forward, it does not include the && of the Args&&.
There are a number of articles on the mechanics and use of std::forward and reference collapsing, here and the Scott Meyers classic on "forwarding (or universal) references".
The first one, but you need to forward your arguments during expansion by using std::forward<T>. This allows your parameter pack to be expanded while properly deducing your arguments.
template <typename Func, typename... Args>
static void WraperFunc(Func func, Args &&... args)
{
// note that we use std::forward<Args>( args )... to perfect forward our arguments
SomeFunc(func, std::forward<Args>( args )...);
}
As an example, say you have a function declared as follows:
template <typename T>
void some_func( T& ) {}
Attempting to use said function with a temporary value or rvalue will fail:
some_func( 5 );
This is due to the fact that 5 is a constant, which cannot be assigned to int&.
Let's say you call your function with the following arguments:
void (*foo)(int, char, float) = /* ... */;
const int i = 0;
char j;
WraperFunc(foo, i, j, 0.42);
In the first case, it's equivalent to calling this function:
void WraperFunc(void (*foo)(int, char, float), int i, char c, float j) { /* ... */ }
In the second case it's equivalent to calling this function:
void WraperFunc(void (*foo)(int, char, float), const int& i, char& c, float&& j) { /* ... */ }
The second is recommended if you want to forward argument while avoiding copies (but use std::forward then!)
I have the following (incomplete, not-working) definition:
template<typename T, std::function<Args(Context&)>... Funcs>
struct constructor
{
T construct(Context& ctx)
{
return T(Funcs(ctx)...);
}
};
What I want is a templated class - the first argument is the constructed type and all following are functions to be called, the user templates with std::functions that are then called to produce the values for the constructor of type T.
I don't see a possibility to make this code work, let beside capturing the return types of the functions. I want the user to use it like this:
std::function<int(Context&)> ind = [](Context&) {return 2;};
Constructor<int, ind> c;
// c.construct(...) returns 2 by calling the constructor int(int) with argument
// ind(ctx) - which returns 2.
This might be roughly what you're looking for. Keep in mind that a std::function can't be a template parameter.
template <typename R> using Generator = std::function<R (Context&)>;
template <typename T, typename Generators, std::size_t... Is>
T constructImpl(Context& ctx, const Generators& generators,
std::index_sequence<Is...>) {
return T(std::get<Is>(generators)(ctx)...);
}
template <typename T, typename... Args>
class Constructor {
std::tuple<Generator<Args>...> generators;
public:
Constructor(Generator<Args>... generators)
: generators(std::move(generators)...)
{}
T construct(Context& ctx) {
return constructImpl<T>(ctx, generators,
std::index_sequence_for<Args...>());
}
};
Usage:
Constructor<int, int> c([](Context&) { return 2; });
int i = c.construct(context);
assert(i == 2);
Types cannot depend on run time data.
Calling std::function<X(Y)> requires run time data. So your type cannot depend on std::function<X(Y)>, so the type cannot be used as a template parameter.
Now, it can depend on a pointer to a global object: that is interestingly enough not run time state as far as C++ is concerned.
As such, your design is fundamentally flawed.
If you want a function such that it returns 2, this works:
template<class...ignored>
struct Constructor {
template<class... also_ignored>
Constructor(also_ignored&&...) {}
template<class... also_ignored>
int construct(also_ignored&&...) { return 2; }
};
this will pass the unit tests described in your OP, with the exception that you cannot pass ind to Constructor as it is not legal. However, dropping it from the type signature doesn't matter.
If you want more power, we could do this:
template<class T, class... Functors>
struct Constructor {
T construct( Context& ctx ) {
return T( Functors{}( ctx )... );
}
};
in this case you need stateless function objects:
struct ind { int operator()(Context&)const{return 2;} };
much like how std::map requires stateless comparison objects.
If your function objects require state, then you need to store a copy of them for Constructor to access (possibly within Constructor), and you might need the tuple and indexes trick to store them. ("indexes trick" is a helpful google)
I think your Construct can just be a function:
template <typename T, typename... Funcs>
T construct(Context& ctx, Funcs... funcs) {
return T(funcs(ctx)...);
}
Whose usage could be in your example could be:
int x = construct<int>(ctx, [](Context& ) { return 2; });