Given typename T
and int N
, the templated value below generates a null function pointer of the type:
int (*) (T_0, ... T_N)
While the code works, I don't like that it pollutes the namespace with the Temp
bootstrap helper - Temp
is required because types can't be enclosed in parentheses. For example, none of the following are valid.
(int (*)((int))
((int (*)(int)))
(int (*)( (I,T)... ))
The last entry shows how I would like to expand T
into a list of N
T
s - which of course isn't valid. It's a trick to make T
depend on I
but with a value only of T
, thanks to the comma operator.
As a workaround, I'm forced to create the one-shot type Temp
templated to make T
depend on int
, or in this case, I
. Its usage as Temp<T,I>
is valid because it doesn't enclose types in parenthesis.
However, like I said, I want to get rid of Temp
because it pollutes the namespace. In the code below I restate the problem and demonstrate some attempted workarounds which sadly, all fail. For the record, I think an equivalence between template <typename T, int> using Temp = T;
and template <... template<typename T1, int N1> typename Temp=T>
should be allowed.
Followup: When I original published this question, I didn't know exactly why extra parentheses were disallowed, and I'm still not sure why some of my attempts failed. For example:
decltype(w<T,N>())...
result_of<w<T,N>()>::type...
I don't see any parentheses around types!
#include <iostream>
#include <typeinfo>
// Problem, #1
// This is a one-shot helper than pollutes the namespace
template <typename T, int>
using Temp = T;
// Idea #1
// Make the one-shot helper actuall useful, where ... represents either
// type or non-type parameters.
// Result
// Not possible.
//template <typename T, ...>
//using Dependent = T;
// Idea #2
// Make the types dependent within the template declaration
// Result
// Probably not possible
//template <typename T, int N, template<typename T1, int N1> typename F=T>
// Idea #6
// Replace the lambda with a struct (not shown)
// Result
// Crashes gcc
template <typename T, int N>
auto a =
[]<size_t... I>
(std::index_sequence<I...>) {
// Problem #2
// Function type declaration won't parse with extra parentheses
//return (int (*)( (I,T)... ))nullptr;
// Idea #3
// Move the templated helper into the function
// Result
// Not possible
//template <typename T, int>
//using Temp = T;
// Idea #4
// Replace the templated helper with a templated lambda which *is*
// allowed inside functions.
// Result
// Still requires parentheses, still breaks function type declaration
//auto w = []<typename T1, int N1>() -> T1 {};
//return (int (*)( decltype(w<T,N>())... ));
// Idea #5
// result_of (which is a template) instead of decltype
// Result
// Doesn't work even without parentheses, not sure why
//return (int (*)( result_of<w<T,N>>... ));
//return (int (*)( result_of<w<T,N>()>::type... ));
// Idea #7
// Use std::function
// Result
// Can't get function pointer from std::function
// Idea #2 implementation
//using F<T,I> = T;
//return (int (*)( F<T,I>... ))nullptr;
// So far, only this works:
return (int (*)( Temp<T,I>... ))nullptr;
}
(std::make_index_sequence<N>{});
int main () {
auto b = a<int, 4>;
std::cout << typeid(b).name() << std::endl;
}
CodePudding user response:
You can replace Temp<T,I>
with std::enable_if_t<(void(I), true), T>
.
Function type declarations won't parse extra parentheses
that actually works! Why?
Types can't be enclosed in parentheses. But the first argument of enable_if_t
is an expression rather than a type, so ( )
is allowed there.