Разрешение перегрузки VC++ 15.5.4
От: Kazmerchuk Pavel  
Дата: 20.01.18 16:48
Оценка:
Код ниже перестал работать после последнего апдейта студии до версии 15.5.4.
Проверил на http://rextester.com VC еще компилирует, GCC нет. Видимо раньше VC был не прав.
Как правильно написать такую перегрузку?
#include <iostream>

template<typename L, typename R>
void (max)(L const& a, R const& b) {

    std::cout << "void (max)(L const& a, R const& b)" << std::endl;
}

template<typename M>
void (max)(typename M::value_type scalar, M const& a) {

    std::cout << "void (max)(typename M::value_type scalar, M const& a)" << std::endl;
}

template<typename T, typename U>
struct EmptyBase {

    typedef T value_type;
    typedef U this_type;
};

template<typename T>
struct Matrix : public EmptyBase<T, Matrix<T> >  {
    
};

int main()
{
    Matrix<double> m;
    double s;    
    max(s, m);
    
    std::cout << "Hello, world!\n";
}

p.s. вариант void (max)(double scalar, M const& a) не предлагать
Re: Разрешение перегрузки VC++ 15.5.4
От: rg45 СССР  
Дата: 20.01.18 22:14
Оценка:
Здравствуйте, Kazmerchuk Pavel, Вы писали:

KP>Код ниже перестал работать после последнего апдейта студии до версии 15.5.4.

KP>Проверил на http://rextester.com VC еще компилирует, GCC нет. Видимо раньше VC был не прав.
KP>Как правильно написать такую перегрузку?
KP>p.s. вариант void (max)(double scalar, M const& a) не предлагать

Ну стандартно же:

https://ideone.com/VeIg1I

#include <iostream>

template <typename, typename, typename = void>
struct Max;

template<typename L, typename R>
void (max)(L const& a, R const& b) {
  Max<L, R>()(a, b);
}

template<typename L, typename R, typename>
struct Max {
  void operator()(L const& a, R const& b) const {
    std::cout << "void (max)(L const& a, R const& b)" << std::endl;
  }
};

template<typename M>
struct Max<typename M::value_type, M> {
  void operator()(typename M::value_type scalar, M const& a) const {
    std::cout << "void (max)(typename M::value_type scalar, M const& a)" << std::endl;
  }
};

template<typename T, typename U>
struct EmptyBase {

    typedef T value_type;
    typedef U this_type;
};

template<typename T>
struct Matrix : public EmptyBase<T, Matrix<T> >  {
    
};

int main()
{
    Matrix<double> m;
    double s;    
    max(s, m);
    max(s, 42);
    
    std::cout << "Hello, world!\n";
}
--
Не можешь достичь желаемого — пожелай достигнутого.
Отредактировано 20.01.2018 22:16 rg45 . Предыдущая версия .
Re[2]: Разрешение перегрузки VC++ 15.5.4
От: Kazmerchuk Pavel  
Дата: 20.01.18 22:43
Оценка:
Здравствуйте, rg45, Вы писали:

R>Ну стандартно же:


Спасибо! Думал все таки можно как-то перегрузкой обойтись. Так было красиво...
Re: Разрешение перегрузки VC++ 15.5.4
От: Vamp Россия  
Дата: 21.01.18 02:39
Оценка:
Во-первых, зачем ты берешь имена функций в скобки?

Во-вторых, например вот так:

#include <iostream>
#include <utility>


template<class T, class E = void>
struct has_value_member : std::false_type {};

template<class T>
struct has_value_member<T, std::void_t<typename T::value_type>> : std::true_type {};


template<typename L, typename R>
std::enable_if_t<!has_value_member<R>::value> max(L const& a, R const& b) {

    std::cout << "void (max)(L const& a, R const& b)" << std::endl;
}

template<typename M>
std::enable_if_t<has_value_member<M>::value> max(typename M::value_type scalar, M const& a) {

    std::cout << "void (max)(typename M::value_type scalar, M const& a)" << std::endl;
}

template<typename T, typename U>
struct EmptyBase {

    typedef T value_type;
    typedef U this_type;
};

template<typename T>
struct Matrix : public EmptyBase<T, Matrix<T> >  {
    
};

const bool has = has_value_member<Matrix<double>>::value;
const bool hasnot = has_value_member<char>::value;

int main()
{
    Matrix<double> m;
    double s;    
    max(s, m);
    char* a, *b;
    max(a, b);
    
    std::cout << "Hello, world!\n";
}
Да здравствует мыло душистое и веревка пушистая.
Re[2]: Разрешение перегрузки VC++ 15.5.4
От: Kazmerchuk Pavel  
Дата: 21.01.18 11:47
Оценка:
Здравствуйте, Vamp, Вы писали:

V>Во-первых, зачем ты берешь имена функций в скобки?

С макросами борюсь )

V>Во-вторых, например вот так:

О, класс! То что надо

Почему исходный вариант не соответствует стандарту? Вроде он логичный и ожидаемое поведение (во всяком случае было у VC)
Re[2]: Разрешение перегрузки VC++ 15.5.4
От: Kazmerchuk Pavel  
Дата: 21.01.18 13:28
Оценка:
Здравствуйте, Vamp, Вы писали:

И еще вопрос. Такое можно совместить с автоматическим выводом типа возвращаемого значения?
В оригинале у меня
template<typename M>
inline auto (min)(typename M::value_type const scalar, M const& a) {

    return detail::expression<detail::Min>(a, scalar);
}
Re[2]: Разрешение перегрузки VC++ 15.5.4
От: Vamp Россия  
Дата: 21.01.18 14:01
Оценка:
R>Ну стандартно же...

А зачем ты столько наворотил? Declaration перед definition, неиспользуемый третий дефолтный параметр шаблона? Вот так все отлично работает:

template<typename L, typename R>
struct Max {
  void operator()(L const& a, R const& b) const {
    std::cout << "void (max)(L const& a, R const& b)" << std::endl;
  }
};
 
template<typename M>
struct Max<typename M::value_type, M> {
  void operator()(typename M::value_type scalar, M const& a) const {
    std::cout << "void (max)(typename M::value_type scalar, M const& a)" << std::endl;
  }
};
 
 
template<typename L, typename R>
void (max)(L const& a, R const& b) {
  Max<L, R>()(a, b);
}
//...
Да здравствует мыло душистое и веревка пушистая.
Re[3]: Разрешение перегрузки VC++ 15.5.4
От: Vamp Россия  
Дата: 21.01.18 14:14
Оценка: 3 (1)
Здравствуйте, Kazmerchuk Pavel, Вы писали:

>Почему исходный вариант не соответствует стандарту? Вроде он логичный и ожидаемое поведение (во всяком случае было у VC)


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

KP>И еще вопрос. Такое можно совместить с автоматическим выводом типа возвращаемого значения?

Можно. Есть несколько способов. Самое прямое — засунуть enable_if_t в шаблонный аргумент вместо возвращаемого значения:

template<typename L, typename R, std::enable_if_t<!has_value_member<R>::value>* = nullptr>
auto max(L const& a, R const& b) {

    std::cout << "void (max)(L const& a, R const& b)" << std::endl;
}
Да здравствует мыло душистое и веревка пушистая.
Re[3]: Разрешение перегрузки VC++ 15.5.4
От: rg45 СССР  
Дата: 21.01.18 14:58
Оценка:
Здравствуйте, Vamp, Вы писали:

V>А зачем ты столько наворотил? Declaration перед definition, неиспользуемый третий дефолтный параметр шаблона? Вот так все отлично работает:


Это же не продакшен код, пример-то отрковенно синтетический. Третий параметр обозначал то, что специализации можно писать с использованием SFINAE. А Declaration перед definition обозначал, что определение primary template может отсутствовать в общем случае.
--
Не можешь достичь желаемого — пожелай достигнутого.
Re[4]: Разрешение перегрузки VC++ 15.5.4
От: Kazmerchuk Pavel  
Дата: 21.01.18 15:05
Оценка:
Здравствуйте, Vamp, Вы писали:

KP>>И еще вопрос. Такое можно совместить с автоматическим выводом типа возвращаемого значения?

V>Можно. Есть несколько способов. Самое прямое — засунуть enable_if_t в шаблонный аргумент вместо возвращаемого значения:

V>
V>template<typename L, typename R, std::enable_if_t<!has_value_member<R>::value>* = nullptr>
V>auto max(L const& a, R const& b) {

V>    std::cout << "void (max)(L const& a, R const& b)" << std::endl;
V>}
V>


На перегрузке с двумя матрицами в качестве аргументов ломается...
http://rextester.com/KQXV95140
max(m, m); //<comment this line for success
Re[5]: Разрешение перегрузки VC++ 15.5.4
От: rg45 СССР  
Дата: 21.01.18 15:53
Оценка: 3 (1)
Здравствуйте, Kazmerchuk Pavel, Вы писали:

KP>На перегрузке с двумя матрицами в качестве аргументов ломается...


https://ideone.com/vYcmFU
--
Не можешь достичь желаемого — пожелай достигнутого.
Re[6]: Разрешение перегрузки VC++ 15.5.4
От: Kazmerchuk Pavel  
Дата: 21.01.18 17:15
Оценка:
Здравствуйте, rg45, Вы писали:

R>Здравствуйте, Kazmerchuk Pavel, Вы писали:


KP>>На перегрузке с двумя матрицами в качестве аргументов ломается...


R>https://ideone.com/vYcmFU


Нет! Ваш вариант был правильный! Для двух матриц должна первая перегрузка срабатывать void (max)(L const& a, R const& b).
Решение Vamp'а ломается.
Re[7]: Разрешение перегрузки VC++ 15.5.4
От: rg45 СССР  
Дата: 22.01.18 12:41
Оценка:
Здравствуйте, Kazmerchuk Pavel, Вы писали:

KP>Нет! Ваш вариант был правильный! Для двух матриц должна первая перегрузка срабатывать void (max)(L const& a, R const& b).

KP>Решение Vamp'а ломается.

Подход с реализацицией шаблонной функции через шаблон класса обладает двумя преимуществами:

1) В случаях, когда подходят одновременно и primary template, и какая-то из специализаций, не возникает коллизии, а просто отдается предпочтение специализации;

2) Этот подход зацищен от "сюрпризов" связанных с нежелательными неявными преобразованиями. Наприемер, если мы предоставляем обычную (возможно частичную) специализацию для какого-то конкретного типы или для семейства типов, порожденных от одного шаблона класса, то применяться такая специализация будет только для этих типов, отсекая возможные неявные преобразования. Если же требуется предоставить какую-то более широкую специализацию, например, для иерархии классов, или для типов, допускающих неявные преобразования, в нашем распоряжении SFINAE, is_base_of, is_convertilbe и целый арсенал других стандартных и рукописных метафункций.

В результате этот подход, несмотря на кажущуюся, на первый взгляд, громоздкость, на практике оказывается гораздо более еффективным. И чем больше специальных случаев, тем больше этот эффект ощущуается. Подход же с перегрузками, при расширеннии, скатывается в какой-то ад и, в конце-концов, приводит к желанию "переписать все нахрен" (с). Вот почему предложенный мной подход я склонен рассматривать как стандартный.
--
Не можешь достичь желаемого — пожелай достигнутого.
Re[7]: Разрешение перегрузки VC++ 15.5.4
От: Vamp Россия  
Дата: 22.01.18 16:17
Оценка:
KP>Нет! Ваш вариант был правильный! Для двух матриц должна первая перегрузка срабатывать void (max)(L const& a, R const& b).
KP>Решение Vamp'а ломается.

У меня нет никакого решения, потому что я не знаю задачи. Я просто показал, как можно включать и выключать перегрузки для приведенного примера. Правильное ли это **решение** в твоем случае? Понятия не имею. На первый взгляд кажется, что вообще нет, потому что непонятно нафиг специализировать max, если можно просто определить оператор > для матрицы? Наверное, у тебя есть свои причины, но мне они не известны.
Да здравствует мыло душистое и веревка пушистая.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.