Say I have a function foo() with takes advantage of c++ variadic templates feature. Now, what's the difference between these implementations:
template <typename... Args>
void foo(Args... args) {
whatever(args...);
}
template<typename... Args>
void foo(Args&... args) {
whatever(args...);
}
template<typename... Args>
void foo(Args... args) {
whatever(&args...);
}
template<typename... Args>
void foo(Args&&... args) {
whatever(std::forward<Args>(args)...);
}
template <typename... Args>
void foo(Args... args) {
whatever(args...);
}
foo gets copies of args and passes them to whatever as l-values.
template<typename... Args>
void foo(Args&... args) {
whatever(args...);
}
foo gets l-value references to args and passes them to whatever as l-values.
template<typename... Args>
void foo(Args... args) {
whatever(&args...);
}
foo gets copies of args and passes them to whatever as pointers to l-values. Be careful of object lifetimes here.
template<typename... Args>
void foo(Args&&... args) {
whatever(std::forward<Args>(args)...);
}
foo gets forwarding references to args. Whether they are l-values or r-values depends on what happens at the call site. They are then perfect-forwarded to whatever, preserving their reference type. Scott Meyers originally called these "universal" references, but forwarding reference is the preferred terminology now.
The first one takes its arguments by value. The second one takes its arguments by lvalue reference (so non-const rvalues cannot be used). The third one also takes its arguments by value, but passes pointers to whatever. The fourth one takes its arguments by forwarding reference and perfect-forwards them to whatever.
There is nothing magical about the variadic templates; the rules are the same as if there were only one argument.
Related
I am working in C++11 and have the following code that compiles. But the problem is that the function func in the below example can also be called with a std::function, lambda, pointer to a function etc.
Instead, I want that func should only be called by a pointer to a non-static member function of any class. That is, I want to restrict this function only member function pointers.
template <typename Callable, typename... Args> void func(Callable&& callable, Args&&... args)
{
}
struct Test
{
int someMember(int x)
{
return x;
}
};
void g(int, int, int)
{
}
int main()
{
func(g, 1, 1, 1); //this works currently but it should be rejected in the modified program
func([](int){}, 42); //this works currently but it should be rejected in the modified program
Test test;
func(&Test::someMember, test, 1);// this works currently and should work in the modified version
}
As we can see in the above program, all of the calls to func works. But I want that only the call func(&Test::someMember, test, 1); should work and the other two calls should be rejected.
So how can I achieve this. Maybe there is a way to use SFINAE or some other metaprogramming technique.
I think static_assert (with std::is_member_function_pointer) is the perfect tool for the situation. No need to change the signature of func, and the error message can be whatever you want, so it's clearer than, for example, a substitution failure.
To call callable, you may use std::mem_fn.
template <typename Callable, typename... Args>
void func(Callable callable, Args&&... args)
{
static_assert(std::is_member_function_pointer<Callable>::value, "callable must be a member function");
std::mem_fn(callable)(args...);
}
Demo
This can be done by setting up the template parameters in such a way that only pointers to member function are accepted(as shown below). In particular, we can have 4 template parameters corresponding to the class, member function parameters, object of that class and finally the arguments passed to that member function.
template<typename className, typename... Param,typename Ret, typename... Args>
void func(Ret (className::*ptrFunc)(Param... param),className& Object, Args... args)
{
(Object.*ptrFunc)(args...); //std::invoke(ptrFunc, Object, args...) in C++17
}
int main()
{
Test test;
func(&Test::someMember, test, 1);//only this form works now
}
Working demo
Maybe there is a way to use SFINAE or some other metaprogramming technique.
That would do it, since we have std::is_member_function_pointer.
template <typename Callable, typename... Args>
typename std::enable_if<std::is_member_function_pointer<Callable>::value, void>::type
func(Callable callable, Args&&... args)
{
}
If the predicate is false, enable_if produces no type, and our template has no return type, making the function non-viable.
The change to pass by value is because it makes to controlling condition simpler, and because we are only passing pointers to members (fairly cheap to copy).
I have a function like this
template <typename... Args> void foo(Args&&... args);
to which I need to add an extra parameter at the end with a default argument. Since the pack needs to come last, I'm thinking of changing the function to
template <typename... Args> void foo(std::tuple<Args&&...> args,
const std::string& name = {});
The question is, what is the best way to pass the arguments in a tuple.
My understanding is that in the std::tuple<Args&&...> the Args are not forwarding references anymore, but strictly rvalue references. How do I get the forwarding references behavior for args wrapped in a tuple, e.g. accept an std::forward_as_tuple and preserve the reference types of the individual tuple elements. Also, what's the best way to pass the tuple here,
std::tuple<Args&&...> args
or
const std::tuple<Args&&...>& args
or
std::tuple<Args&&...>&& args
?
And do I need to use std::forward on the tuple elements inside the function, or simply std::get them?
My understanding is that in the std::tuple<Args&&...> the Args are not forwarding references anymore
Correct.
but strictly rvalue references
Yes, unless Args are specified explicitly, in which case reference collapsing can turn them into lvalue references, i.e., foo<int&>(...) will result in Args&& -> int& && -> int&.
what is the best way to pass the arguments in a tuple.
That depends on the intended usage of foo. If you don't need to know what Args... exactly are, you can probably get away with:
template <typename Tuple>
void foo(Tuple&& args, const std::string& name = {});
In such a case, individual types are still accessible using std::tuple_element_t<N, std::decay_t<Tuple>>.
If you do want to know Args... inside foo (without any additional levels of abstraction), you probably want to deduce the exact types, without any referenceness:
template <typename.... Args>
void foo(std::tuple<Args...>&& args, const std::string& name = {});
Note that if someone uses std::forward_as_tuple with lvalues and rvalues inside, the value categories will be stored in Args and you can still forward those arguments using std::forward (std::forward is not limited to forwarding references only, think of it as a conditional cast).
Also, what's the best way to pass the tuple here
Probably Tuple&& as suggested earlier. If not, then again it depends on the usage. If you use const std::tuple<Args...>&, then by looking at the list of overloads for std::get, you'll see that the the value category and constness propagates to the return value of std::get (modulo reference collapsing). The same is with std::tuple<Args...>&&. Also, using the latter, you will have to use a tuple rvalue as an argument (foo(std::forward_as_tuple(...), ...) as opposed to foo(my_tuple, ...)).
An alternative solution would be to accept a parameter pack, and detect whether the last parameter is something that can be bound by const std::string& or not:
#include <string>
#include <utility>
#include <tuple>
#include <type_traits>
struct dummy {};
template <typename... Args>
void foo_impl(Args&&... args)
{
const std::string& s = std::get<sizeof...(Args) - 1>(std::forward_as_tuple(std::forward<Args>(args)...));
}
template <typename... Args>
auto foo(Args&&... args)
-> std::enable_if_t<std::is_constructible<std::string, std::tuple_element_t<sizeof...(Args), std::tuple<dummy, Args...>>>{}>
{
foo_impl(std::forward<Args>(args)...);
}
template <typename... Args>
auto foo(Args&&... args)
-> std::enable_if_t<!std::is_constructible<std::string, std::tuple_element_t<sizeof...(Args), std::tuple<dummy, Args...>>>{}>
{
foo_impl(std::forward<Args>(args)..., "default");
}
DEMO
Let's say we have a class template like this:
template<typename F>
class A
{
public:
template<typename... Args>
A(F f, Args... args)
{ /* Do something... */ }
};
And now I want to use it in some way like this one:
A<int(int)> a(::close, 1);
Now the question: is there any way to omit the <int(int)> because a compiler can know this information for the ::close? There is no need to save the "design" of the template.
As for concrete task, I need to design a template of a class. Objects of this class could take a function and parameters for this function at construction time and call this function later.
No, you (currently) cannot. The standard way of doing this is by creating "make_like" function (such as make_pair, make_optional ...):
template<typename F, typename... Args>
A<std::decay_t<F>> make_A (F &&f, Args&&... args) {
return {std::forward<F>(f), std::forward<Args>(args)...};
}
C++17 will introduce template argument deduction for class which will allow you to do exactly what you want (see also Barry's answer below).
Thanks to the adoption of template parameter deduction for constructors, in C++17, you'll be able to just write:
A a(::close, 1);
Before that, you'll just need to write a factory to do the deduction for you:
template <class F, class... Args>
A<std::decay_t<F>> make_a(F&& f, Args&&... args) {
return {std::forward<F>(f), std::forward<Args>(args)...};
}
auto a = make_a(::close, 1);
This is a little verbose, but at least you don't need to worry about efficiency - there will be no copies made here thanks to RVO.
You cannot omit the arguments of a template class, unless they are defaulted. What you can do is have a maker function which deduces the argument and forwards this argument to the template class, returning an object of the appropriate instantiation.
template<typename F, typename... Args>
A<F> make_A(F f, Args&&... args) {
return A<F>(f, std::forward<Args>(args)...);
}
I can't figure out how to pass member function with variadic template arguments to std::thread constructor. I have a method that receives function and its arguments and need to pass them to other method which is invoked in new thread and calls passed function there.
Here is simplified version:
class Test
{
public:
template<typename Function, typename... Args>
void Run(Function&& f, Args&&... args)
{
std::thread t(&Test::Operation, this, f, args...); // how???
t.detach();
}
template<typename Function, typename... Args>
void Operation(Function&& f, Args&&... args)
{
f(args...);
}
};
Test test;
test.Run([](const std::string& msg) { std::cout << msg; }, "Hi!");
There is something wrong in passing arguments this way, I get the following error: 'std::thread::thread': no overloaded function takes 4 arguments. How can I do this?
The problem here is that when you pass &Test::Operation to the thread constructor, it can't deduce the template parameters for &Test::Operation. (If you want to understand why this deduction cannot be done, you should probably ask a separate question.) The point is that you need to explicitly specify the template arguments for &Test::Operation.
This will look like this:
template<typename Function, typename... Args>
void Run(Function&& f, Args&&... args)
{
std::thread t(&Test::Operation<std::decay_t<Function>, std::decay_t<Args>...>,
this, std::forward<Function>(f), std::forward<Args>(args)...);
t.detach();
}
I added perfect forwarding for you: it's important because you don't want to perform an unnecessary copy, right?
But why do we need the decay_t? It's because the thread constructor decays its arguments before storing copies of them in the new thread's internal storage, so, for example, if you pass in "Hi!", then the deduced type is const char (&)[4], but it will become a const char* once decayed, and the decay is irreversible, so Test::Operation must not be expecting a const char (&)[4], which cannot be initialized from the decayed const char*. So Test::Operation must be specified to take the decayed type.
You also probably want perfect forwarding during the actual invocation.
Link: http://coliru.stacked-crooked.com/a/c9d04c03a3758b51
I'd want to implement a function caller that works just like the thread constructor. For example
std::thread second (bar,0);
will start a thread which calls bar with the single argument 0. I would like to do the same thing, but I do not know how.
For example, given:
void myFunc(int a){
cout << a << endl;
}
I would like:
int main() {
caller(myFunc,12);
}
to call myFunc with the parameter 12.
std::bind will make a callable object from any callable object with an arbitrary set of parameters, just as the thread constructor does. So just wrap that in a function that calls it:
template <typename... Args>
auto caller(Args &&... args) {
return std::bind(std::forward<Args>(args)...)();
}
Note that the auto return type requires C++14 or later. For C++11, you'll have to either return void, or specify the type:
auto caller(Args &&... args)
-> decltype(std::bind(std::forward<Args>(args)...)())
If all you want to do is call an arbitrary function with an arbitrary argument, that's just a template on both types:
template <typename Function, typename Arg>
void call_with_one(Function&& f, Arg&& arg) {
f(std::forward<Arg>(arg));
}
which you can expand to call with any number of args by making it variadic:
template <typename Function, typename... Arg>
void call_with_any(Function f, Arg&&... args) {
f(std::forward<Arg>(args)...);
}
Or really f should be a forwarding reference as well:
template <typename Function, typename... Arg>
void call_with_any(Function&& f, Arg&&... args) {
std::forward<Function>(f)(std::forward<Arg>(args)...);
}
Note that this will only work with functions and objects that implement operator(). If f is a pointer-to-member, this will fail - you will have to instead use std::bind as Mike Seymour suggests.