Create object using parameters pack in template - c++

I'd like to create template function that would create object basing on template typename and parameters pack.
I created a function that is supposed to create object based on typename from template, and I would also like to pass parameters pack to that template i order to pass parameters to constructor. Is this correct?:
template<typename TComponent, typename... Args>
void CreateComponent(Args... args)
{
std::shared_ptr<TComponent> component = std::make_shared<TComponent>(args ...);
}
I also wanted to pass those parameters to another fucntion like this:
template<typename TComponent, typename... Args>
void AddComponent(Args... args)
{
m_world->AddComponent<TComponent, Args>(m_id, args...);
}
But compiler returns an error " 'args' parameter pack must be expanded in this context"
Is it even possible to achieve what I want to achieve ?

But compiler returns an error " 'args' parameter pack must be expanded in this context"
Yes: you've forgotten to expand the types
m_world->AddComponent<TComponent, Args...>(m_id, args...);
// ...................................^^^
As pointed by Jarod42, according to the circumstances, you could avoid to explicit the Args... expansion
m_world->AddComponent<TComponent>(m_id, args...);
// no more Args...
and let the compiler deduce the types through args... (but we should see the AddComponent() definition).
Anyway, I don't see errors in your CreateComponents() function but, as correctly says François Andrieux in a comment, you don't using perfect forwarding.
It's a too-great argument to explain in an answer but, this way, you're renouncing to move semantics advantages (that is: you, potentially, make some unnecessary copies).
The following is your CreateComponents() function enabling perfect forwarding
template <typename TComponent, typename ... Args>
void CreateComponent (Args && ... args)
{ // .....................^^ forwarding reference added
std::shared_ptr<TComponent> component
= std::make_shared<TComponent>(std::forward<Args>(args)...);
} // ..............................^^^^^^^^^^^^^^^^^^^^^^^^

Related

Restrict function template for member functions only

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).

How to forward packed variadic arguments

I have a function that accepts variadic arguments packed into a tuple
template <class... Args>
void Bottom(tuple<Args&&...> t)
{
}
Is Args&& a forwarding reference? I.e. would the rules for reference collapsing apply or am I just appending && to every argument in the pack?
And say I want to call this function from a function that certainly gets forwarding references:
template <class... Args>
void Top(Args&&... args) {
// 1. Bottom<Pack...>();
// 2. Bottom<Pack&&...>();
}
which syntax would be best if I don't want to alter the arguments, 1 or 2?
EDIT
I'm only using tuple to showcase a class that packs my parameters. The actual packing classes vary in different levels of the call hierarchy. The idea of using using_fwd_as_tuple is cool as a resource to find what the library does at this case.
I'd say none. I'd use std::forward_as_tuple and let compiler do the deduction:
template <class... Args>
void Top(Args&&... args) {
Bottom(std::forward_as_tuple(args...));
}
No, tuple<Args&&...> t are not forwarding references. They can only be present as top-level arguments.
You are not appending anything, you are attempting to match the arguments. Such function only accepts tuples (by value) which contain r-value references.
Example
#include <tuple>
using namespace std;
template <class... Args>
void Bottom(tuple<Args&&...> t)
{
}
// Type your code here, or load an example.
int main(){
double var=0.0;
tuple<int,double&,char&&> tup1{1,var,'c'};
//#1
//Bottom(tup1);
tuple<int&&,double&&,char&&> tup2{1,0.0,'c'};
//#2
//Bottom(tup2);
//#3
Bottom(std::move(tup2));
}
Does not compile since the arguments cannot be matched.
Does not compile either. Eventhough the arguments do match, the tuple itself is passed by value, in this case by copy and the copy constructor is deleted in presence of r-value tuple members.
Moving is fine, this instantiates this template:
template<>
void Bottom<int, double, char>(std::tuple<int &&, double &&, char &&> t)
{
}

How can I convert each parameter in a variadic function template to another type and obtain its address?

This question is similar to others that have been asked here, but with a small twist. I have a regular function something like this:
void Bar(std::initializer_list<Base*> objects);
Now I want to create a function template that wraps each parameter in a type that derives from Base and passes them to the function above. Something like:
template <class... Params> void Foo(Params... parameters)
{
Bar({&Wrapper<Params>(parameters)...});
}
(The class Wrapper is specialized for various types.) This code actually compiles in MSVC but the compiler issues a warning because I'm taking the address of an rvalue (which is disallowed by the standard). Is there an easy, standards conformant way to achieve the same thing? (I think I can do this with tuples, integer_sequences, and a helper function, but I'd like to avoid that if possible.)
The issue is the Wrapper<T> instances must exist at some address. The easy way to do this is to construct a std::tuple<Wrapper<Params>...> instance. The annoying part is that you have to extract the contents back out using std::get<N>. In C++14, std::index_sequence exists to help you with this matter.
template <class... Params, std::size_t... Idx>
void FooImpl(std::tuple<Wrapper<Params>...>& tup, std::index_sequence<Idx...>)
{
Bar({ (&std::get<Idx>(tup))... });
}
template <class... Params>
void Foo(Params... parameters)
{
std::tuple<Wrapper<Params>...> tup(Wrapper<Params>(parameters)...);
FooImpl(tup, std::make_index_sequence<sizeof...(Params)>());
}
If your Bar takes const Wrapper<T>*s, another option is to use C++'s constant ref rules to your advantage.
template <class... Params>
void FooImpl(const Wrapper<Params>&... parameters)
{
Bar({ (&parameters)... });
}
template <class... Params>
void Foo(Params... parameters)
{
FooImpl(Wrapper<Params>(parameters)...);
}

Deduction of the function

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

Can someone explain how to use result_of within template?

I'm trying to create a delayable call object. Something along the lines of (pseudo-code):
template <class FN>
struct delayable_call
{
return-type-of-FN call(); // <-- I'd like to use result_of here.
template<class ArgTypes...>
delayable_call(FN* pFn, ArgTypes... args);
FN* fn;
args-saving-struct;
};
I tried using result_of::type for the return type of call, but get errors during instantiation of the template because apparently the argument types need to be specified separately.
Instantiation:
int foo(bool, double); // function prototype.
delayable_call<int(bool, double)> delayable_foo(foo, false, 3.14); // instantiation
The error messages and documentation I've read about result_of seem to indicate that the argument types must also be specified. So instead of result_of<FN>::type, I'd need to specify result_of<FN(bool, double)>::type. This does actually fix the compilation problem I'm having, but breaks the generality of the template.
So, how can I use result_of with a template parameter when the template parameter represents the function signature?
template <class FN> struct delayable_call;
template<class R, class...Args> delayable_call<R(Args...)>{
typedef R(*)(Args...) pFN;
replace your delayable_call with a specialization, and you will extrace both R and Args.... You need Args... anyhow to store the parameters.
However, a library-strength delayable call will end up using type erasure. The easiest way is a simple std::function<R()> where you shove a lambda into it:
int foo(double);
double x = 7;
std::function<int()> delayed_foo = [x]{ return foo(x); }
and capture by value unless you really, really mean it to capture by reference.
You could deduce R via:
template<typename Fn, typename... Args>
std::function< typename std::result_of<Fn(Args...)>::type()>
make_delayed_call( Fn&& fn, Args&&... args ) {
return [=]{ return fn(std::move(args)...); }
}
which should deduce your R from the callable object and the arguments. This captures everything by copy -- capture by move requires either more boilerplate, or C++14.