Home > Mobile >  Convert static_assert in if constexpr for type checking to C 14
Convert static_assert in if constexpr for type checking to C 14

Time:05-22

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";
}

Demo

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";
}
  • Related