I'm sorry for the title, I don't know how to call it...
I'm trying to make a one liner of the caller() function (C 20).
template <typename T>
void func() {
std::cerr << typeid(T).name() << std::endl;
}
void caller(const int &_i) {
switch(_i) {
case 1:
func<uint8_t>();
break;
case 2:
func<uint16_t>();
break;
case 3:
func<uint32_t>();
break;
case 4:
func<uint64_t>();
break;
}
}
int main() {
caller(1);
caller(2);
return 0;
}
I tried with struct helper but it seems this case do not fit.
I also tried a different approach with caller<i>() and the use of std::conditionnal_t, but did not find how to use it in this specific case.
template <size_t ID>
void func() {
using T = std::conditionnal_t<ID==0, uint8_t, [...]>;
std::cerr << typeid(T).name() << std::endl;
}
Is there multiple ways to do this, and if so, which are they?
CodePudding user response:
This is as close as I can get to caller being a branchless one liner (use with care, no out of bound checks)
#include <array>
#include <functional>
#include <iostream>
template <typename T>
void func()
{
std::cout << typeid(T).name() << "\n";
}
static constexpr std::array<void(*)(), 4> funcs
{
func<std::uint8_t>,
func<std::uint16_t>,
func<std::uint32_t>,
func<std::uint64_t>
};
void caller(const std::size_t index)
{
funcs[index]();
}
int main()
{
caller(1ul);
return 0;
}
CodePudding user response:
If you can provide the value to caller at compile time, you can do something like this:
template<std::size_t>
struct int_type_id;
template<>
struct int_type_id<0> { using type = std::uint8_t; };
template<>
struct int_type_id<1> { using type = std::uint16_t; };
template<>
struct int_type_id<2> { using type = std::uint32_t; };
template<>
struct int_type_id<3> { using type = std::uint64_t; };
template <size_t ID>
void caller() {
using T = typename int_type_id<ID>::type;
func<T>();
// you can reduce that to a one liner:
// func<typename int_type_id<ID>::type>();
}
Then call it like that:
int main() {
caller<1>();
caller<2>();
return 0;
}
CodePudding user response:
Using std::variant
and std::type_identity
to do type dispatch.
using VType = std::variant<std::type_identity<uint8_t>,
std::type_identity<uint16_t>,
std::type_identity<uint32_t>,
std::type_identity<uint64_t>>;
static const std::unordered_map<int, VType> dispatcher = {
{1, std::type_identity<uint8_t>{}},
{2, std::type_identity<uint16_t>{}},
{3, std::type_identity<uint32_t>{}},
{4, std::type_identity<uint64_t>{}},
};
void caller(const int &_i) {
return std::visit([&](auto v){
func<typename decltype(v)::type>();
}, dispatcher.at(_i));
}
Disclaimer: Pay attention to run-time performance if you care about it.