3

Consider the following code:

#include <tuple>

template <class Result, class Function, class... Types>
Result f(Function func, Types... values)
{
    return std::get<0>(std::make_tuple(func(values)...));
}

template <class... Types>
int g(const Types... values)
{
    return std::get<0>(std::make_tuple(f<Types>([](int n){return n;}, values)...));
}

int main()
{
    return g(42);
}

Under g++ 4.8.1, it produces:

mangling.cpp: In instantiation of ‘g(const Types ...) [with Types = int]::__lambda0’:
mangling.cpp:12:50:   required from ‘struct g(const Types ...) [with Types = int]::__lambda0’
mangling.cpp:12:77:   required from ‘int g(const Types ...) [with Types = int]’
mangling.cpp:17:16:   required from here
mangling.cpp:12:57: sorry, unimplemented: mangling argument_pack_select
     return std::get<0>(std::make_tuple(f<Types>([](int n){return n;}, values)...));
                                                         ^
mangling.cpp: In instantiation of ‘struct g(const Types ...) [with Types = int]::__lambda0’:
mangling.cpp:12:77:   required from ‘int g(const Types ...) [with Types = int]’
mangling.cpp:17:16:   required from here
mangling.cpp:12:57: sorry, unimplemented: mangling argument_pack_select
mangling.cpp:12:57: sorry, unimplemented: mangling argument_pack_select
mangling.cpp:4:8: error: ‘Result f(Function, Types ...) [with Result = int; Function = g(const Types ...) [with Types = {int}]::__lambda0; Types = {int}]’, declared using local type ‘g(const Types ...) [with Types = {int}]::__lambda0’, is used but never defined [-fpermissive]
 Result f(Function func, Types... values)

Is there a workaround to avoid this problem ? Has it been reported and corrected in g++ 4.8.2 or 4.9.0 ?

EDIT: I've just reported the bug here: http://gcc.gnu.org/bugzilla/show_bug.cgi?id=60130

Vincent
  • 57,703
  • 61
  • 205
  • 388
  • Gives an ICE in gcc 4.9. –  Feb 10 '14 at 06:34
  • Vincent: Post an example of the actual problem you're trying to solve. @DanielFrey's answer is correct: if you're just trying to avoid the ICE, all you have to do is pull the lambda outside of the pack-expansion. (If you need it `constexpr`, the solution is the same. I can post code, but I'd rather not distract from Daniel's answer before you've actually told us all your secret requirements.) – Quuxplusone Feb 10 '14 at 20:30
  • @Quuxplusone I am dealing with a code relying heavily on the most awful/elegant metaprogramming tricks and I have isolated the problem in this example. But basically, I need to do exactly the same thing that causes trouble in the provided example (this is not an XY problem). – Vincent Feb 10 '14 at 20:53
  • Accept Daniel's answer, then. :) (Translation: yes, you are dealing with an XY problem, and until you tell us X the only thing we can do is solve Y for you, which apparently isn't very useful to you.) – Quuxplusone Feb 10 '14 at 21:13

1 Answers1

3

Do you need a new lambda for each of the expanded parameters? Otherwise this fixes it:

template <class... Types>
int g(const Types... values)
{
    auto func = [](int n){return n;};
    return std::get<0>(std::make_tuple(f<Types>(func, values)...));
}

Live example

Daniel Frey
  • 55,810
  • 13
  • 122
  • 180
  • @Vincent Not sure if C++1y is an option for you and if it really works with `constexpr`, but [maybe this](http://coliru.stacked-crooked.com/a/da04662afe354ab0) helps? – Daniel Frey Feb 10 '14 at 23:21
  • @Daniel In C++1y, you could just add `constexpr` to the function you wrote in your answer! Anyway, in C++11, you can constexprify anything with suitable use of helper functions. I.e., you'd implement `g` as `return ghelper([](int n){return n;}, values...);` where `ghelper` is implemented in the obvious way. – Quuxplusone Feb 11 '14 at 01:23