Reputation: 4412
In C++, it's possible to use a type as a template parameter, e.g:
template <typename T>
void MyFn();
It's also possible to use a non-type as a template parameter in some cases, e.g.:
template <int64_t T>
void MyFn2();
My question is whether it's possible to have a "generic" template parameter that can be both? Like:
template <TypenameOrint64_t T>
void MyFn3();
such that both MyFn3<42>
and MyFn3<double>
would be acceptable.
An example of how I might use this:
template <typename ValType, ValType Head, ValType ...Tail>
struct ListS{
template <typename OutType, template <ValType ArgType> class Fn>
using MapHead = ListS<OutType, Fn<Head>::val, Tail...>;
};
template<int64_t N>
struct SquareS{
static constexpr const int64_t val = N * N;
};
using Sqrd = ListS<int64_t, 3, 4>::MapHead<int64_t, SquareS>;
static_assert(std::is_same<Sqrd, ListS<int64_t, 9, 4>>::value, "Values don't match");
The above is a very rough sketch of a compile-time list of values along with a single compile-time "function" on it. Would it be possible to make something like that also support lists of types, not just lists of non-type template param compatible values, without just duplicating all the code?
Upvotes: 2
Views: 100
Reputation: 66200
Is it possible to have a “generic” template parameter in C++, that can be either a non-type template parameter or a type?
Short answer: no.
Long answer.
No. The best I can imagine to mix types and values is wrap values in types, using std::integral_constant
, by example.
So, your desired code, could be written (C++17) almost as follows
#include <utility>
template <typename ...>
struct ListS;
template <typename ValType, ValType Head, ValType ...Tail>
struct ListS<std::integral_constant<ValType, Head>,
std::integral_constant<ValType, Tail>...>
{
template <template <auto> class Fn, typename OutType = ValType>
using MapHead = ListS<std::integral_constant<OutType, Fn<Head>::value>,
std::integral_constant<OutType, Tail>...>;
};
template <auto N>
struct SquareS : public std::integral_constant<decltype(N), N*N>
{ };
int main ()
{
using T1 = ListS<std::integral_constant<long long, 3ll>,
std::integral_constant<long long, 4ll>>;
using T2 = T1::MapHead<SquareS>;
using T3 = ListS<std::integral_constant<long long, 9ll>,
std::integral_constant<long long, 4ll>>;
static_assert( std::is_same_v<T2, T3> );
}
Pre C++17 you can't use auto
for the type of the template values so you should make some simple corrections.
Upvotes: 3
Reputation: 739
You could use function overloading and the auto
type deduction that came with C++17
to accomplish something similar.
template<typename myType>
auto myFn3(myType value){
return value;
}
template<auto value> //takes any non-type parameter
auto myFn3(){
return value;
}
int main(){
auto test1_normal = myFn3(3);
auto test1_cast = myFn3<double>(3); //able to perform a cast
auto test1_auto = myFn3<3>();
return 0;
}
Upvotes: 2