This question on the object generator pattern got me thinking about ways to automate it.
Essentially, I want to automate the creation of functions like std::make_pair
, std::bind1st
and std::mem_fun
so that instead of having to write a different function for each template class type, you could write a single variadic template template function that handles all cases at once. Usage of this function would be like:
make<std::pair>(1, 2); // equivalent to std::make_pair(1, 2)
make<std::binder2nd>(&foo, 3); // equivalent to std::bind2nd(&foo, 3);
Is it possible to write this function make
? I have tried this, but it doesn't work in GCC 4.5 or 4.6:
template <template <typename...> class TemplateClass, typename... Args>
TemplateClass<Args...> make(Args&&... args)
{
return TemplateClass<Args...>(std::forward<Args>(args)...);
}
If I try to call (e.g) make<std::pair>(1, 2)
I just get
error: no matching function for call to 'make(int, int)'
Have I got the syntax wrong anywhere here?
Or is this right and GCC is wrong?
Or is this just fundamentally impossible in C++0x?
[edit]
Proposal N2555 seems to suggest that this is allowed and GCC claims to have implemented it in GCC4.4.
Variadic templates are class or function templates, that can take any variable(zero or more) number of arguments. In C++, templates can have a fixed number of parameters only that have to be specified at the time of declaration. However, variadic templates help to overcome this issue.
What is Perfect Forwarding. Perfect forwarding allows a template function that accepts a set of arguments to forward these arguments to another function whilst retaining the lvalue or rvalue nature of the original function arguments.
std::forwardReturns an rvalue reference to arg if arg is not an lvalue reference. If arg is an lvalue reference, the function returns arg without modifying its type.
That's exactly right. I would expect it to work. So I think that GCC is in error with rejecting that. FWIW:
#include <utility>
template <template <typename...> class TemplateClass, typename... Args>
TemplateClass<Args...> make(Args&&... args)
{
return TemplateClass<Args...>(std::forward<Args>(args)...);
}
int main() {
make<std::pair>(1, 2);
}
// [js@HOST2 cpp]$ clang++ -std=c++0x main1.cpp
// [js@HOST2 cpp]$
This is probably a GCC quirk. I can get the following to work with a dev snapshot (I don't have a copy of 4.6 right now):
template<
template<typename...> class TemplateClass
, typename... Args
, typename Result = TemplateClass<Args...>
// Also works with the arguably more correct
// , typename Result = TemplateClass<
// typename std::decay<Args>::type...
// >
>
Result
make(Args&&... args)
{ /* as before */ }
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With