как специализировать шаблон, используя enable_if_t, чтобы принимать преобразование int в enum

Вопрос или проблема

Я пытаюсь написать специализированный конструктор, который бы принимал целочисленный аргумент и преобразовывал его в перечисление. Моя попытка приведена ниже, но она завершается ошибкой. Другие шаблонные кандидаты отклоняются, и это правильно. Есть идеи, как это исправить?

#include <type_traits>

template<typename T>
class SomeType
{
public:
    T val;

    template <typename U>
        SomeType<T>(typename std::enable_if_t<std::is_integral<U>::value>::type _u) : 
        val(T(_u)) { }
    SomeType<T>(const T& _t) : val(_t) { }
    SomeType<T>(const SomeType<T>& _t) : val(_t.val) { }
    SomeType<T>() : val() { }
};

void foo()
{
    typedef enum { ala=0, ola} MyEnumType;
    SomeType<int> s1;     // ОК
    SomeType<int> s2(2);  // ОК
    SomeType<MyEnumType> e1;   // ОК
    SomeType<MyEnumType> e2(MyEnumType::ola);  // ОК
    SomeType<MyEnumType> e3(MyEnumType(0));  // ОК
    SomeType<MyEnumType> e4(0); 
        // ОШИБКА: 
        // кандидат: template<class U> SomeType<T>::SomeType(typename std::enable_if<std::is_integral<U>::value, void>::type::type)
        // SomeType<T>(typename std::enable_if_t<std::is_integral<U>::value>::type _u) : val(NativeType(_u)) { }
    // ^~~~~~~~~~~
    // вывод шаблонных аргументов/замена не удалась:
    // не удалось вывести шаблонный параметр 'U'
}

Я пробовал разные шаблоны использования для enable_if_t, но ни один из них не сработал.

Ответ или решение

Давайте разберем, как можно исправить вашу реализацию шаблонного конструктора с использованием enable_if_t, чтобы он корректно принимал целочисленные аргументы и конвертировал их в перечисления. Ваша текущая реализация сталкивается с проблемой, связанной с тем, что компилятор не может вывести тип шаблона U из конструктора, поскольку вы используете typename std::enable_if_t в качестве параметра.

Решение проблемы

Для начала следует изменить сигнатуру конструктора. Вместо использования typename std::enable_if_t, мы будем использовать статическую проверку в самом конструкторе с помощью enable_if и сделаем его зависимым от параметра U. Это позволит компилятору правильно разрешать U в зависимости от переданного аргумента.

Вот как это можно сделать:

#include <type_traits>

template<typename T>
class SomeType
{
public:
    T val;

    // Специализированный конструктор для int
    template <typename U, typename = typename std::enable_if<std::is_integral<U>::value>::type>
    SomeType(U _u) : val(T(_u)) { }

    // Конструктор для типа T
    SomeType(const T& _t) : val(_t) { }
    SomeType(const SomeType<T>& _t) : val(_t.val) { }
    SomeType() : val() { }
};

void foo()
{
    enum MyEnumType { ala = 0, ola }; // Определение перечисления
    SomeType<int> s1;                      // OK
    SomeType<int> s2(2);                   // OK
    SomeType<MyEnumType> e1;               // OK
    SomeType<MyEnumType> e2(MyEnumType::ola); // OK
    SomeType<MyEnumType> e3(MyEnumType(0));   // OK
    SomeType<MyEnumType> e4(0);                // Теперь компилируется корректно
}

Объяснение изменений

  1. Тип U и enable_if: Во втором параметре шаблонного конструктора мы добавили typename = typename std::enable_if<std::is_integral<U>::value>::type. Это позволяет нам использовать U, который будет выведен компилятором на основе переданного аргумента.

  2. Отказ от typename перед std::enable_if_t: Мы используем структуру enable_if в стиле SFINAE (Substitution Failure Is Not An Error), чтобы корректно обрабатывать только целочисленные типы.

  3. Конструктор для T: Конструктор для типа T остался без изменений, он по-прежнему позволяет инициализировать объект SomeType значениями, которые соответствуют типу T.

Вывод

Теперь данный вариант конструктора компилируется и позволяет конвертировать целочисленные значения в перечисляемые типы. Этот подход минимизирует потенциальные ошибки и явным образом задает условия для использования конструктора. Надеюсь, этот пример поможет вам должным образом реализовать необходимую функциональность в вашем коде.

Оцените материал
Добавить комментарий

Капча загружается...