Решение проблемы отсутствия поддержки специализации псевдонимов типов в C

#c #template-specialization #type-alias

Вопрос:

Я хочу иметь возможность ссылаться на различные типы, используя литералы в качестве идентификаторов.

 template<auto>
using type = void;

template<>
using type<0> = int;

template<>
using type<1> = char;

template<>
using type<2> = string;

int main()
{
  type<0> var0;
  type<1> var1;
  type<2> var2;
}
 

Это приводит к тому, что компилятор выдает мне ошибки, поскольку специализация псевдонимов типов еще не поддерживается в C . (Технологии, необходимой для реализации такой функции, просто не существует)

Ответ №1:

Это сделает это и даст вам необходимый синтаксис. Примечание. Я явно использую std::size_t, чтобы избежать специализации на других типах, а затем на числах.

 #include <string>
#include <type_traits>

//-------------------------------------------------------------------
// hide all the boiler plate in a namespace
// use structs for partial specializations

namespace details
{
    template<std::size_t N>
    struct type_s { using type = void; };

    template<> struct type_s<0> { using type = int; };
    template<> struct type_s<1> { using type = char; };
    template<> struct type_s<2> { using type = std::string; };
}

//-------------------------------------------------------------------
// now you can use a full template for alias

template<std::size_t N>
using type_t = typename details::type_s<N>::type;

//-------------------------------------------------------------------

int main()
{
    type_t<0> var0{ 42 };
    type_t<1> var1{ 'A' };
    type_t<2> var2{ "Hello World!" };

    static_assert(std::is_same_v<type_t<0>, int>);
    static_assert(std::is_same_v<type_t<1>, char>);
    static_assert(std::is_same_v<type_t<2>, std::string>);

    static_assert(std::is_same_v<decltype(var0), int>);
    static_assert(std::is_same_v<decltype(var1), char>);
    static_assert(std::is_same_v<decltype(var2), std::string>);
}
 

Ответ №2:

Частичная специализация не допускается в шаблонах псевдонимов, однако вместо этого вы можете использовать std::conditional :

 #include <type_traits>
#include <string>
// ...

template <auto X>
using type = std::conditional_t<X == 0, int,
             std::conditional_t<X == 1, char,
             std::conditional_t<X == 2, std::string,
                 void>>>;
 

Комментарии:

1. Привет, милая, еще один инструмент для моего набора инструментов

Ответ №3:

К счастью, я нашел обходной путь, который использует специализацию на классах, которая поддерживается в C :

 template<auto>
struct TypeAliasWrapper;

template<>
struct TypeAliasWrapper<0>{using type = int;};

template<>
struct TypeAliasWrapper<1>{using type = char;};

template<>
struct TypeAliasWrapper<2>{using type = string;};

int main()
{
  TypeAliasWrapper<0>::type var0;
  TypeAliasWrapper<1>::type var1;
  TypeAliasWrapper<2>::type var2;
}