Home > database >  "transform apply" - using tuple elements as parameters to one function to construct a para
"transform apply" - using tuple elements as parameters to one function to construct a para

Time:08-18

Given the following:

constexpr auto t = std::make_tuple(3, 2, 1);
template<auto x>
auto InnerF() {return -x;}

auto OuterF(auto... args) {return (args   ...);}

I can use the elements of t as parameters to InnerF directly:

InnerF<std::get<0>(t)>();

But I want to be able to write

std::apply([](auto... arg) { return OuterF(InnerF<arg>()...); }, t);

But this does not work, I get

<source>:29:44: error: no matching function for call to 'InnerF'
std::apply([](auto... arg) { return OuterF(InnerF<arg>()...) ;}, t);
.
.
.
<source>:29:44: error: no matching function for call to 'InnerF'
std::apply([](auto... arg) { return OuterF(InnerF<arg>()...) ;}, t);
                                           ^~~~~~~~~~~
<source>:23:6: note: candidate template ignored: invalid explicitly-specified argument for template parameter 'x'
auto InnerF() {return -x;}

I don't understand why the arg is considered invalid, I tried modifying the syntax a number of ways and reimplementing apply myself, but couldn't crack it - is there any way to make this work?

CodePudding user response:

The error is because InnerF is expecting a non-type template parameter. Those must be compile-time constants, which auto... arg are not. Using gcc 12.1, I get this more helpful error message:

<source>:10:59: error: no matching function for call to 'InnerF<arg#0>()'
   10 |     std::apply([](auto... arg) { return OuterF(InnerF<arg>()...); }, t);
      |                                                ~~~~~~~~~~~^~
<source>:4:6: note: candidate: 'template<auto x> auto InnerF()'
    4 | auto InnerF() {return -x;}
      |      ^~~~~~
<source>:4:6: note:   template argument deduction/substitution failed:
<source>:10:59: error: 'arg#0' is not a constant expression
   10 |     std::apply([](auto... arg) { return OuterF(InnerF<arg>()...); }, t);
      |                                                ~~~~~~~~~~~^~
<source>:10:59: note: in template argument for type 'int'

The solution is to write InnerF like so:

auto InnerF(auto x) { return -x; }

And call std::apply like this:

std::apply([](auto... arg) { return OuterF(InnerF(arg)...); }, t);
  • Related