I am working to downgrade a C 17 project to C 14. I found the following code:
#include <iostream>
#include <type_traits>
#include <typeinfo>
template <bool flag = false>
void get_assertion_message()
{
static_assert(flag, "unknown type");
}
template <typename T>
const char* get_name()
{
if constexpr (std::is_same<T, int>::value)
{
return "Integer";
}
else if constexpr (std::is_same<T, double>::value)
{
return "Double";
}
else
{
get_assertion_message();
return "Unknown";
}
}
int main()
{
std::cout << get_name<int>() << std::endl;
}
It uses if constexpr
to check the type and return the type name accordingly. If no type matches, it calls a template function get_assertion_message
which uses static_assert
.
I was thinking of applying a solution based on my previous question here: https://stackoverflow.com/a/72300411/4688321. The solution was based on an approach called "tag dispatch".
But, it seems the compilation fails due to static_assert
, and doesn't work as expected:
#include <iostream>
#include <type_traits>
#include <typeinfo>
template <bool flag = false>
void get_assertion_message()
{
static_assert(flag, "unknown type");
}
const char* get_name(std::integral_constant<int, 0>)
{
return "Integer";
}
const char* get_name(std::integral_constant<int, 1>)
{
return "Double";
}
const char* get_name(std::integral_constant<int, 2>)
{
get_assertion_message();
return "Unknown";
}
template<int N, class T, class... V>
struct dispatch_constant;
template<int N, class T>
struct dispatch_constant<N, T>
{
static constexpr int value = N;
};
template<int N, typename T, class U, class... V>
struct dispatch_constant<N, T, U, V...>
{
static constexpr int value = std::is_same<T, U>::value ? N - sizeof...(V) - 1 : dispatch_constant<N, T, V...>::value;
};
template <typename T>
const char* get_name()
{
using dispatch_t = std::integral_constant<int, dispatch_constant<2, T, int, double>::value >;
return get_name(dispatch_t{});
}
// template <typename T>
// const char* get_name()
// {
// if constexpr (std::is_same<T, int>::value)
// {
// return "Integer";
// }
// else if constexpr (std::is_same<T, double>::value)
// {
// return "Double";
// }
// else
// {
// get_assertion_message();
// return "Unknown";
// }
// }
int main()
{
std::cout << get_name<int>() << std::endl;
}
I am using GCC 5.4 for compilation in C 14. Is it possible to change the above "tag dispatch" solution so that it doesn't fail due to static_assert
? Please provide suggestions.
CodePudding user response:
You can split the function template up and make specializations:
template <typename T, bool flag = false>
const char* get_name() {
static_assert(flag, "unknown type");
return nullptr;
}
template <>
const char* get_name<int>() {
return "Integer";
}
template <>
const char* get_name<double>() {
return "Double";
}
CodePudding user response:
const char* get_name(std::integral_constant<int, 2>)
is not a template function, so there is no instantiation involved and static_assert
will always be triggered. Try turning it into a template function
template<std::size_t N>
const char* get_name(std::integral_constant<int, N>)
{
get_assertion_message();
return "Unknown";
}