Variadic template templates and perfect forwarding

C++C++11Variadic TemplatesTemplate Templates

C++ Problem Overview


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.

C++ Solutions


Solution 1 - C++

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]$

Solution 2 - C++

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 */ }

Solution 3 - C++

This is quite wrong- take make_shared, for example. The point of make_shared is that there are run-time efficiency savings for using it. But what would happen if I tried to use make<std::shared_ptr>? Don't think that would quite work out. Or how about types where only some of the constructor arguments are template arguments, and the rest aren't? For example, make<std::vector, int>(other_vector.begin(), other_vector.end()); - the types of the iterators don't participate, but you pass them in anyway.

It's impossible to write a generic make function.

As for the Standard, well, it could easily have been removed since then. You'd have to check the FDIS.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionPeter AlexanderView Question on Stackoverflow
Solution 1 - C++Johannes Schaub - litbView Answer on Stackoverflow
Solution 2 - C++Luc DantonView Answer on Stackoverflow
Solution 3 - C++PuppyView Answer on Stackoverflow