I have a C++ template class (in Qt) that should handle a list of custom items. This class has a simple member function that is supposed to call the constructor of the template type and add the created item to the list.
void CustomList::addElement(void)
{
T *element = new T();
// ...
}
But I have a problem : I'd like this function to be able to call overloaded constructors.
I thought I could give it the arguments that should be used in the constructor. So it would be called with as arguments a "copy" of the arguments given to addElement().
Except that I don't know how many of them there are, no more than their types. Any simple way I could do it ?
So it would be called with as arguments a "copy" of the arguments
given to addElement().
Why copies when you can use the original arguments?
With C++11 you can use variadic templates and perfect forwarding:
template <typename... Args>
void CustomList::addElement(Args&&... args)
{
T *element = new T(std::forward<Args>(args)...);
// ...
}
Without proper C++11 support you will have to overload the addElement function (template) for every amount of arguments until a sensible limit is reached. I.e.
template <typename Arg1>
void CustomList::addElement(Arg1 const& arg1)
{
T *element = new T(arg1);
// ...
}
template <typename Arg1, typename Arg2>
void CustomList::addElement(Arg1 const& arg1, Arg2 const& arg2)
{
T *element = new T(arg1, arg2);
// ...
}
// [...]
Related
I have the following structure that lets me bind the virtual functions of ExampleInterfaceClass to a class that implements the virtual functions from ExampleInterfaceClass:
struct ExampleStruct {
ExampleInterfaceClass *instance = nullptr;
ExampleInterfaceClass *(*InstantiateScript)(void);
void (*DestroyScript)(ExampleStruct *);
template <typename T> void Bind(void)
{
InstantiateScript = []()
{
return static_cast<ExampleInterfaceClass *>(new T());
};
DestroyScript = [](ExampleStruct *exampleStruct)
{
delete exampleStruct->instance;
exampleStruct->instance = nullptr;
};
}
};
Now I want to forward variadic arguments from Bind() to the instantiation of the class that implement the interface. I know I have to change the template to the following
template <typename T, typename... T_args> void Bind(T_args &&... args)
But I have trouble to pass the variadic arguments to the instantiation of the class because of the lambda.
Without the lambda I think I could use the following:
return static_cast<ExampleInterfaceClass *>(new T(std::forward<T_args>(args)...));
But the compiler tells me that 'args' are not captured.
How can I capture the variadic arguments and forward them?
You can capture variadic arguments in the same way you would capture any other arguments. However, care must be taken to not capture them by value, as it will make them const qualified. Here is an example:
#include <utility>
struct L {};
void k(L&& );
template<class... T> void foo(T&&... t)
{
auto l = [&t...]() { k(std::forward<T>(t)...); };
}
void a()
{
L l{};
foo(l); // errror
foo(L{}); // OK
}
Please note, once you start capturing in lambda (no matter how), it is no longer convertible to function pointer and you'd have to store it in std::function object if you need to type-erase it.
Need to create variadic template<T> function with different arg types that will call constructor of T with given arguments, sort of like when creating a thread but reverse (when creating a thread, its constructor calls function at given funct pointer).
So in pseudo code it should look something like this
template<typename T>
T* CreateNew( ARGS ) {
return new T( ARGS ); //Constructor Gets Same Arguments That Were
} //Passed To The Function
Want this to behave like when creating threads, when they call functions with their arguments that are of different types (which I am unsure how to achive).
Its not entirely clear to me but I think you want to look up variadic templates, e.g.:
template <typename T, typename... Args>
T* CreateNew(Args... args) {
return new T(args...);
}
Adding Example:
#include <iostream>
class A {
public:
A(int a){
std::cout<<__PRETTY_FUNCTION__<<std::endl;
}
A(std::string a){
std::cout<<__PRETTY_FUNCTION__<<std::endl;
}
A(int a,std::string b){
std::cout<<__PRETTY_FUNCTION__<<std::endl;
}
};
template<typename T, typename... Args>
T* create(Args... args){
return new T(args...);
}
int main(){
A b(1);
A c("a");
A d(1,"a");
A* bp = create<A>(1);
A* cp = create<A>("a");
A* dp = create<A>(1,"a");
// This code leaks
return 0;
}
Note that because the changes are kept as minimal as possible, we still return a T* here as the original code. Most of the time, this is not a good idea since ownership is passed via raw pointers. Therefore, as suggested by the comments, you might want to use a std::unique_ptr, which would make your CreateNew function basically equivalent to std::make_unique.
The correct way to write this function is
template <typename T, typename... Args>
T* CreateNew(Args&&... args) {
return new T(std::forward<Args>(args)...);
}
Without the forwarding reference Args&& and without std::forward, the original value categories of the passed arguments will not be propagated to T's constructor, causing potential performance and semantic problems.
I'm trying to create a variadic template class that looks like this :
template <class... Args>
class Message
{
private:
std::function<void(Args...)> _function;
public:
//stuff
};
I want to have an option to bind so the user can bind any function (with corresponding arguments) when he wants. I've tried this approach (this function is a part of the Message class, so Args... comes from the template argument of the class):
template<class T>
void Message::bindFunction(void(T::*function)(Args... args), T* ownerPtr)
{
//This doesn't work
_function = boost::bind(function,args, ownerPtr);
}
However the above doesn't work, I've tried to create the tuple from the args in the bind function, but the compiler keeps saying:
<args_0> undeclared identifier.
(If I pass more arguments it changes)
From the user's point of view it should look like this:
class Foo
{
public:
void test2(int a, float b, double c)
{
std::cout << "bla";
}
};
int main()
{
Foo f;
Message<int,float,double> Mess;
Mess.bindFunction(&Foo::test2, &f);
}
I've seen a lot of articles talking about forwarding the parameters, however most of the answers confuse me more than I am already with different template structures without explaining them.
Use a lambda because they're much nicer (Live Demo (C++11)):
template<class T>
void bindFunction(void(T::*function)(Args...), T* ownerPtr)
{
_function = [function, ownerPtr](Args... args)
{
(ownerPtr->*function)(args...);
};
}
We are capturing the function pointer and pointer to instance of the class with [function, ownerPtr] in the lambda declaration.
The lambda accepts a list of arguments whose types are specified in the variadic template for the Message class: Args... args.
Internally we call the function using our instance with the (ownerPtr->*function) syntax, and then pass in the arguments by expanding the parameter pack (args...)
To call the function you might write something like this:
void callFunction(Args&&... args)
{
_function(std::forward<Args>(args)...);
}
We use perfect forwarding to pass our arguments to the std::function<void(Args...)> member.
Is it possible to initialize all elements of std::tuple by the same argument, using the non-default constructors of the underlying types?
template <typename... TElements>
struct Container {
// I'd wish to be able to do something like this:
Container(Foo foo, Bar bar)
: tuple(foo, bar)
{}
std::tuple<TElements...> tuple;
};
The point is that I don't know the tuple size (it's templated by a variadic parameter), so I can't duplicate the arguments as many times as I need. The only thing I know is that all types in TElements have a constructor taking Foo and Bar as arguments and don't have a default constructor.
The clearest way is just to construct each element in the tuple constructor argument list:
template <typename... TElements>
struct Container {
Container(Foo foo, Bar bar)
: tuple(TElements{foo, bar}...)
{}
std::tuple<TElements...> tuple;
};
This will result in move (or copy) constructing each element of the tuple from its corresponding constructor parameter; if this is unacceptable you could use piecewise construction:
template <typename... TElements>
struct Container {
Container(Foo foo, Bar bar)
: tuple(std::piecewise_construct, (sizeof(TElements), std::tie(foo, bar))...)
{}
std::tuple<TElements...> tuple;
};
Unfortunately in this case we have to do some kind of gymnastics (here sizeof and a comma operator) to get the variadic list TElements mentioned and ignored.
with double parameter pack expansion you can (try to) construct each element of a given tuple class with all given parameters to a function:
template <class T> struct tuple_construct_t;
template <class... Ts> struct tuple_construct_t<std::tuple<Ts...>> {
template <class... Args>
static std::tuple<Ts...> make_tuple(Args&&... args) {
//this is the central part - the double pack expansion
return std::make_tuple(Ts{args...}...);
}
};
// a little free helper function...
template <class Tup, class... Args>
Tup construct_tuple(Args&&... args) {
return tuple_construct_t<Tup>::make_tuple(std::forward<Args>(args)...);
}
And then somewhere in the code:
typedef std::tuple<NoDefault1, NoDefault2> myTuple;
auto t = construct_tuple<myTuple>(Foo{}, Bar{});
full working example: Link
Edit:
Since #Rakvan deleted his answer, I'll preserve the second (correct) part of it:
template <class ... Ts, class ... Args>
std::tuple<Ts...> cartesian_make_tuple(Args && ... args)
{
return std::make_tuple(Ts{args...}...);
}
here is a working exaple
We want to do variadic expansion (to get just the right amount of parameters), but we have to put a ‘hint’ to tie the expansion to whichever pack it is we want to match:
template<typename Dummy, typename Value>
Value depends(Value&& value)
{ return std::forward<Value>(value); }
template<typename... Elements>
void example()
{
// naive attempt to construct all the elements from 0:
// std::tuple<Elements...> t { 0... };
// now expansion is tied to the Elements pack
std::tuple<Elements...> t { depends<Elements>(0)... };
// with two arguments:
std::tuple<Elements...> t { { depends<Elements>(0), depends<Elements>(1) }... };
}
I have a member function with a variable number of parameters, stored in a std::function, and I want to bind the instance and get an independent function object.
template <class T, class R, class... Args>
void connect(const T& t, std::function<R(const T&, Args...)> f) {
std::function<R(Args...)> = /* bind the instance c into the function? */
}
// ...
Class c;
connect(c, &Class::foo);
For a fixed number of arguments I'd use std::bind, but I don't see how to do this for variadic parameters.
I hope this is what you were trying to achieve:
#include <iostream>
#include <cstdarg>
#include <functional>
class Class {
public:
void foo(...)
{
std::cout << "foo" << std::endl;
}
};
template <typename RES_T>
using ClassVarMemFunT = RES_T (Class::*)(...);
// Without typedef:
// template <class... ARGS, class CLASS_T, class RES_T>
// std::function<RES_T(ARGS...)> connect(CLASS_T& object, RES_T (CLASS_T::*funPtr)(...))
template <typename... ARGS, typename CLASS_T, typename RES_T>
std::function<RES_T(ARGS...)> connect(CLASS_T& object, ClassVarMemFunT<RES_T> funPtr)
{
std::function<RES_T(ARGS...)> resultFun = [&object, funPtr](ARGS&&... args) -> RES_T {
return (object.*funPtr)(std::forward<ARGS>(args)...);
};
return resultFun;
}
int main() {
Class c;
auto funPtr1 = connect<int, float>(c, &Class::foo);
funPtr1(10, 2.f);
auto funPtr2 = connect<double, float, int>(c, &Class::foo);
funPtr2(2., 2.f, 10);
return 0;
}
In my implementation connect expects the actual argument types as template parameters. The connect function returns an std::function that expects arguments with ARGS... types.
connect has two parameters:
one for the object that has a variadic function (object).
one for the member function pointer that points to the variadic function we would like to call (funPtr).
We cannot use std::bind in the implementation (we could, but it would involve a lot of boilerplate to add as many std::placeholders as we need based on the ARGS).
So I introduce a lambda instead, that expects the actual ARGS typed arguments. We can return the lambda as an std::function and we are good to go.
https://godbolt.org/z/7cx3rcYh8
I created a version that can print out the variadic list as well:
https://godbolt.org/z/nMxj7Wh9j