Reputation: 748
I am trying to do something like this:
struct Foo {
int _val;
Foo(int v) : _val(v){}
};
struct Bar {
const std::string &_name;
Bar(const std::string &name) : _name(name) {}
};
template<typename T>
struct Universal {
T _t;
Universal(...) : _t(...) {}
};
// I want to use Universal for Foo abd Bar in the same way:
Universal<Foo> UF(9); // 9 is for Foo
Universal<Bar> UB("hello"); // "hello" is for bar
In the code above, I would like to forward all parameters in Universal's constructor to T's constructor.
How could I do it?
Upvotes: 1
Views: 1407
Reputation: 28987
You need to make Universal
constructor be a variadic template, and use a parameter pack and perfect forwarding.
template<typename T>
struct Universal {
T _t;
template <typename... Args>
Universal(Args&&... args) : _t(std::forward<Args>(args)...) {}
};
Unfortunately as AndyG notes in the comments, this means that if you try and copy a non-const Universal
object, the forwarding version gets preferred - so you need explicit const and non-const copy constructors!
template<typename T>
struct Universal {
T _t;
template <typename... Args>
Universal(Args&&... args) : _t(std::forward<Args>(args)...) {}
Universal(const Universal& rhs): _t(rhs._t) {}
Universal( Universal& rhs): _r(rhs._t) {}
// ... but not move constructors.
};
or use the SFINAE approach shown in this answer, to make sure the default constructor is preferred.
Upvotes: 5
Reputation: 75707
Simple:
template<typename T>
struct Universal {
T _t;
Universal(const T& val) : _t(val) {}
};
iff performance is of concern or if you want to support move only types you can forward the parameter:
template<typename T>
struct Universal {
T _t;
template <class U>
Universal(U&& val) : _t(std::forward<U>(val)) {}
};
Please note we need a template parameter U
for the ctor in order for the forwarding to work. T&&
would be just a rvalue reference.
If you want to get more fancy, you can construct in place:
template<typename T>
struct Universal {
T _t;
template <class... Args>
Universal(Args&&... args) : _t(std::forward<Args>(args)...) {}
};
As AndyG suggested in a comment, extra work would need to be done if you want cpy and mv ctors to work as expected.
The rule is: keep it simple unless there is a good reason justifying the complications. I think that the first variant is more than enough for you.
Upvotes: 0