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);