Как использовать enable_if для включения функций-членов на основе параметра шаблона класса - PullRequest
12 голосов
/ 11 ноября 2010

В коде:

template<class T>
struct is_builtin
{
    enum {value = 0};
};

template<>
struct is_builtin<char>
{
    enum {value = 1};
};

template<>
struct is_builtin<int>
{
    enum {value = 1};
};

template<>
struct is_builtin<double>
{
    enum {value = 1};
};

template<class T>
struct My
{
    typename enable_if<is_builtin<T>::value,void>::type f(T arg)
    {
        std::cout << "Built-in as a param.\n";
    }


    typename enable_if<!is_builtin<T>::value,void>::type f(T arg)
    {
        std::cout << "Non - built-in as a param.\n";
    }
};

struct A
{
};

int main()
{
    A a;
    My<int> m;
    My<A> ma;
    m.f(1);
    ma.f(a);
    return 0;
}

Я получаю сообщение об ошибке:

error C2039: 'type' : is not a member of 'std::tr1::enable_if<_Test,_Type>'    

Очевидно, я не понимаю, как использовать enable_if. Я думал о том, что могу включить одну или вторую функцию-член из набора функций-членов во время компиляции, но она не работает. Может ли кто-нибудь объяснить мне, как это сделать правильно?
1010 * Отредактированный *
Что я действительно не могу понять, так это почему в одном из этих определений нет typedef. Компилятор не может найти его и не скомпилирует.

Ответы [ 4 ]

13 голосов
/ 11 ноября 2010

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

Вам либо нужно

  • сделать функцию-член взамен шаблона функции-члена и использовать enable_if в параметрах шаблона функции-члена или

  • переместить функцию-член f в класс политики и специализировать шаблон класса, используя enable_if.

1 голос
/ 11 июля 2017

Вы можете исправить свой код, используя модифицированный enable_if

template < typename T >
struct __Conflict {};

template <bool B, class T = void>
struct __enable_if { typedef __Conflict<T> type; };

template <class T>
struct __enable_if<true, T> { typedef T type; };

Пример использования:

template <typename T>
class Lazy
{
public:
    void _ctor(bool b);
    void _ctor(typename __enable_if<!std::is_same<T, bool>::value, T>::type);
};

template <typename T>
void Lazy<T>::_ctor(bool b)
{
    std::cout << "bool " << b << std::endl;
};

template <typename T>
void Lazy<T>::_ctor(typename __enable_if<!std::is_same<T, bool>::value, T>::type t)
{
    std::cout << "T " << t << std::endl;
};

int main(int argc, char **argv)
{
    Lazy<int> i;
    i._ctor(10);
    i._ctor(true);

    Lazy<bool> b;
    b._ctor(true);

    return 0;
}
0 голосов
/ 16 февраля 2016

Вот как это работает (обратите внимание, что для удобства я заменил вашу черту is_builtin на std::is_arithmetic и использовал дополнительные компоненты C ++ 11, но это работает в любом случае):

template<class T>
struct My
{
    template<typename T_ = T, std::enable_if_t<std::is_arithmetic<T_>::value>* = nullptr>
    void f(T_ arg)
    {
        std::cout << "Built-in as a param.\n";
    }

    template<typename T_ = T, std::enable_if_t<!std::is_arithmetic<T_>::value>* = nullptr>
    void f(T_ arg)
    {
        std::cout << "Non - built-in as a param.\n";
    }
};

DEMO

Важнейшей частью является приведение параметра шаблона в непосредственный контекст с помощью параметра шаблона функции по умолчанию T_, который равен параметру шаблона класса T. Подробнее см. этот вопрос .

0 голосов
/ 11 ноября 2010

enable_if ожидает метафункцию.Для использования bool вам нужно enable_if_c.Я удивлен, что вы не получаете ошибок, объясняющих эту проблему.

Вы можете исправить свою метафункцию, объявив typedef типа type внутри себя, который просто сам по себе.Тогда вы можете использовать boost::enable_if<is_builtin<T>>::type

...