Как использовать std :: is_integral ‹› для выбора реализации?

Я пытаюсь вернуть int64_t, если std::is_integral<>::value верно.

В противном случае я хотел бы вызвать to_int64t() для объекта.

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

КОД

#include <type_traits>
#include <cstdint>

template<class T,bool is_integral_type>
int64_t to_int64t( const T& t )
{
        return t;
}

template<class T>
int64_t to_int64t<T,std::is_integral<T>::value>( const T& t )
{
        return t;
}

template<class T>
int64_t to_int64t<T,!std::is_integral<T>::value>( const T& t )
{
        return t.to_int64t();
}

int main()
{
        int64_t i = 64;
        auto x = to_int64t( i );
}

person kfmfe04    schedule 24.03.2013    source источник
comment
возможный дубликат: stackoverflow.com/ questions / 12073689 /   -  person legends2k    schedule 03.10.2013


Ответы (2)


Шаблоны функций не могут быть частично специализированными, и, как правило, не рекомендуется использовать специализацию шаблонов функций.

Один из способов добиться того, чего вы хотите, - использовать метод, называемый диспетчеризацией тегов, который в основном заключается в предоставлении функции пересылки, которая выбирает правильную перегрузку на основе значения дополнительного фиктивного аргумента:

#include <type_traits>
#include <cstdint>

template<class T>
int64_t to_int64t( const T& t, std::true_type )
{
    return t;
}

template<class T>
int64_t to_int64t( const T& t, std::false_type )
{
    return t.to_int64t();
}

template<class T>
int64_t to_int64t( const T& t )
{
    return to_int64t(t, std::is_integral<T>());
}

int main()
{
    int64_t i = 64;
    auto x = to_int64t( i );
}

Другая возможность - использовать классическую технику SFINAE, основанную на std::enable_if. Вот как это может выглядеть (обратите внимание, что, начиная с C ++ 11, аргументы шаблона по умолчанию в шаблонах функций разрешены):

#include <type_traits>
#include <cstdint>

template<class T, typename std::enable_if<
    std::is_integral<T>::value>::type* = nullptr>
int64_t to_int64t( const T& t )
{
    return t;
}

template<class T, typename std::enable_if<
    !std::is_integral<T>::value>::type* = nullptr>
int64_t to_int64t( const T& t )
{
    return t.to_int64t();
}

int main()
{
    int64_t i = 64;
    auto x = to_int64t( i );
}

Еще одна возможность, хотя и более подробная, состоит в том, чтобы определить шаблоны вспомогательных классов (которые могут быть частично специализированы) в пространстве имен detail и предоставить глобальный сервер пересылки - я бы не использовал этот метод для этого варианта использования, но я показываю его, потому что он может пригодятся в связанных дизайнерских ситуациях:

#include <type_traits>
#include <cstdint>

namespace detail
{
    template<class T, bool = std::is_integral<T>::value>
    struct helper { };

    template<class T>
    struct helper<T, true>
    {
        static int64_t to_int64t( const T& t )
        {
            return t;
        }
    };

    template<class T>
    struct helper<T, false>
    {
        static int64_t to_int64t( const T& t )
        {
            return t.to_int64t();
        }
    };
}

template<class T>
int64_t to_int64t( const T& t )
{
    return detail::helper<T>::to_int64t(t);
}

int main()
{
    int64_t i = 64;
    auto x = to_int64t( i );
}
person Andy Prowl    schedule 24.03.2013
comment
Ой, это прекрасно. :) - person 0x499602D2; 24.03.2013
comment
Второй компилируется для вас? Я получаю ошибку C4519: аргументы шаблона по умолчанию разрешены только в шаблоне класса - person Alon; 24.03.2013
comment
@Alon: аргументы шаблона по умолчанию в шаблонах функций, которые были введены в C ++ 11, поэтому вы должны компилировать с параметром std=c++11 (возможно, вам придется обновить свой компилятор до последней версии, если это не поддерживается) - person Andy Prowl; 24.03.2013
comment
Спасибо, я полагаю, это доступно только в gcc (я использую VS) - person Alon; 24.03.2013
comment
@Alon: Хорошо, если вы используете VS, вам понадобится VS2012. В любом случае вы можете сделать этот аргумент шаблона по умолчанию аргументом function по умолчанию, который менее элегантен, но все равно будет работать - person Andy Prowl; 24.03.2013
comment
@AndyProwl: я использую 2012, но он все еще не компилируется; что ты имеешь в виду? переместить его из сигнатуры шаблона во второй параметр сигнатуры функции? тогда пользователь должен это набрать? - person Alon; 24.03.2013
comment
@Alon: Хм, тогда похоже, что поддержка VS2012 все еще довольно ограничена. Да, это то, что я имел в виду, и нет, пользователь не должен не вводить его, потому что он имеет значение по умолчанию (= nullptr). Проблема с этой версией заключается в том, что пользователь может ввести ее, что нежелательно. Однако до тех пор, пока пользователь будет передавать только один аргумент, это будет работать так, как задумано. - person Andy Prowl; 24.03.2013
comment
@AndyProwl: Кроме того, есть ли шанс показать пример того, как поместить это в аргументы функции? - person Alon; 24.03.2013
comment
Спасибо, +1 за терпение :) - person Alon; 24.03.2013
comment
@AndyProwl: не могли бы вы объяснить компилятор? если enable_if не работает, он просто не выбирает эту функцию? - person Alon; 24.03.2013
comment
@Alon: Да, это называется SFINAE (отказ замещения не является ошибкой): компилятор пытается создать экземпляр сигнатуры шаблона функции, и в случае неудачи он просто отбрасывает соответствующую функцию из набора перегрузки и рассматривает только другие жизнеспособные функции. - person Andy Prowl; 24.03.2013
comment
@AndyProwl: и 1, и 3 являются отправкой тегов. 1 - это отправка тегов по экземпляру, а 3 - отправка тегов по типу. ~ Источник - person legends2k; 03.10.2013

Вы можете просто использовать std::enable_if:

template<class T, typename std::enable_if<std::is_integral<T>::value, int>::type = 0>
int64_t to_int64t( const T& t )
{
        return t;
}

template<class T, typename std::enable_if<!std::is_integral<T>::value, int>::type = 0>
int64_t to_int64t( const T& t )
{
        return t.to_int64t();
}
person Stephan Dollberg    schedule 24.03.2013
comment
Думаю, это лучшая реализация, чем принятая? Не работает? - person John; 14.12.2020