про enable_if и почему не компилируется.
От: collider  
Дата: 18.09.17 19:01
Оценка:
#include <vector>
#include <list>
#include <algorithm>


namespace stdx
{
    template<class T>
    struct _is_std_list: public std::false_type
    {
    };
    
    template<class T, class AllocatorT >
    struct _is_std_list<std::list<T, AllocatorT> > : public std::true_type
    {
    };


    //1 вариант
    template<class ListType,class = std::enable_if_t<_is_std_list<ListType>::value > >
    inline void sort(ListType& _List)
    {
        _List.sort();
    }

    template<class ListType, class  = std::enable_if_t<!_is_std_list<ListType>::value > >
    inline void sort(ListType& _List)
    {
        std::sort(std::begin(_List),std::end(_List));
    }


/*      //2-й вариант
    template<class ListType >
    inline std::enable_if_t<_is_std_list<ListType>::value > sort(ListType& _List)
    {
        _List.sort();
    }

    template<class ListType >
    inline std::enable_if_t<!_is_std_list<ListType>::value > sort(ListType& _List)
    {
        std::sort(std::begin(_List), std::end(_List));
    }
*/

}


int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])
{
    int nRetCode = 0;

    {
        std::vector<long> test = {1,-1,2,10,3};
        stdx::sort(test); //Error    C2995    'void stdx::sort(ListType &)': function template has already been defined    test    d : \prjvc\test\test\test.cpp    122
    }
    {
        std::list<long> test = { 1,-1,2,10,3 };
        stdx::sort(test); //Error    C2995    'void stdx::sort(ListType &)': function template has already been defined    test    d : \prjvc\test\test\test.cpp    122
    }
    return nRetCode;
}


Почему 1-й вариант в отличие от 2-го не компилируется?
В чем разница?
Re: про enable_if и почему не компилируется.
От: Constructor  
Дата: 18.09.17 19:50
Оценка:
Здравствуйте, collider, Вы писали:

C>Почему 1-й вариант в отличие от 2-го не компилируется?

C>В чем разница?

В первом варианте две шаблонные функции отличаются только значениями по умолчанию у одного из шаблонных параметров. Т.е. имеют одинаковые прототипы и с точки зрения механизма перегрузки идентичны.
Во втором случае у шаблонных функций отличаются возвращаемые значения, что делает их различимыми с точки зрения механизма перегрузки (точнее, специальных правил перегрузки шаблонных функций, описанных в параграфе 14.5.6.1 Function template overloading [temp.over.link] стандарта).
Re[2]: про enable_if и почему не компилируется.
От: collider  
Дата: 18.09.17 20:49
Оценка:
Здравствуйте, Constructor, Вы писали:

C>Здравствуйте, collider, Вы писали:


C>>Почему 1-й вариант в отличие от 2-го не компилируется?

C>>В чем разница?

C>В первом варианте две шаблонные функции отличаются только значениями по умолчанию у одного из шаблонных параметров. Т.е. имеют одинаковые прототипы и с точки зрения механизма перегрузки идентичны.

C>Во втором случае у шаблонных функций отличаются возвращаемые значения, что делает их различимыми с точки зрения механизма перегрузки (точнее, специальных правил перегрузки шаблонных функций, описанных в параграфе 14.5.6.1 Function template overloading [temp.over.link] стандарта).

Честно говоря звучит как то не очень убедительно.


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

То есть если в для каждой специализации в 1-м варианте существует один валидный вариант- то какие проблемы вызвать его?

Я тут случайно набрел на реализацию std::pair в VS 2015
Ну так там примерно такое же колдовство, только почему то оно работает )

template<class _Other1,
class _Other2,
class = enable_if_t<is_constructible<_Ty1, const _Other1&>::value
&& is_constructible<_Ty2, const _Other2&>::value>,
enable_if_t<is_convertible<const _Other1&, _Ty1>::value
&& is_convertible<const _Other2&, _Ty2>::value, int> = 0>
constexpr pair(const pair<_Other1, _Other2>& _Right)
: first(_Right.first), second(_Right.second)
{ // construct from compatible pair
}

template<class _Other1,
class _Other2,
class = enable_if_t<is_constructible<_Ty1, const _Other1&>::value
&& is_constructible<_Ty2, const _Other2&>::value>,
enable_if_t<!is_convertible<const _Other1&, _Ty1>::value
|| !is_convertible<const _Other2&, _Ty2>::value, int> = 0>
constexpr explicit pair(const pair<_Other1, _Other2>& _Right)
: first(_Right.first), second(_Right.second)
{ // construct from compatible pair
}
Re[3]: про enable_if и почему не компилируется.
От: reversecode google
Дата: 18.09.17 20:56
Оценка:
Здравствуйте, collider, Вы писали:

что бы много не писать,все уже расписано до нас

https://stackoverflow.com/questions/6972368/stdenable-if-to-conditionally-compile-a-member-function/25483768#25483768
Re[3]: про enable_if и почему не компилируется.
От: Constructor  
Дата: 19.09.17 05:25
Оценка:
Здравствуйте, collider, Вы писали:

C>Во 2-м варианте шаблонные функции не отличаются возвращаемым типом.

С т.з. компилятора отличаются.

C>Он просто валиден только в одной функции для каждой конкретной специализации.

Об этом компилятор узнает только в тот момент, когда начнет перебирать эти перегрузки, чтобы подобрать нужную.

C>Я тут случайно набрел на реализацию std::pair в VS 2015

C>Ну так там примерно такое же колдовство, только почему то оно работает )
Присмотритесь внимательнее, это колдовство использует std::enable_if_t не только для задания значения по умолчанию для 3-го шаблонного параметра, но и для задания типа 4-го параметра (который является параметром-нетипом со значением по умолчанию, равным 0). Т.е. у двух шаблонных перегрузок конструктора std::pair отличаются прототипы. Ничто не мешает и Вам использовать такую технику на грани фантастики.
Отредактировано 19.09.2017 6:00 Constructor . Предыдущая версия .
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.