Re[6]: Зачем нужны concept?
От: Evgeny.Panasyuk Россия  
Дата: 03.10.20 03:12
Оценка: 3 (2)
Здравствуйте, Videoman, Вы писали:

V>Для примера у нас есть класс представляющий эелемент какого-нибудь json элемента и у него конструкторы. Приходится писать так:

V>
V>        template <typename BoolType, std::enable_if_t<is_bool_v<BoolType>, int> = 0>
V>        Element(BoolType value);
V>        template <typename IntType, std::enable_if_t<is_int_v<IntType>, int> = 0>
V>        Element(IntType value);
V>        template <typename UintType, std::enable_if_t<is_uint_v<UintType>, int> = 0>
V>        Element(UintType value);
V>        template <typename FloatType, std::enable_if_t<is_float_v<FloatType>, int> = 0>
V>        Element(FloatType value);
V>        ...
V>

V>С концептами это должно превратиться во что-то типа:
V>
V>        template <BoolType ValueType>
V>        Element(ValueType value);
V>        template <IntType ValueType>
V>        Element(ValueType value);
V>        template <UintType ValueType>
V>        Element(ValueType value);
V>        template <FloatType ValueType>
V>        Element(ValueType value);
V>        ...
V>


В этом примере не раскрывается основная фишка концепций в плане overload resolution, а именно частичное упорядочивание требований по степени специфичности (после нормализации). Да, во втором варианте меньше буков, но по структурной сложности одно и то же.
(Как альтернатива, в C++17 можно это же сделать всё внутри одного метода через if constexpr — структурная сложность всё равно подобная, но всё же проще и лаконичнее чем enable_if)

Ниже пример где уже видно частичное упорядочивание, и без дополнительных трюков на голом enable_if не получится:
#include <type_traits>
using namespace std;

template<typename T> concept Arithmetic = is_arithmetic_v<T>;
template<typename T> concept Integral = Arithmetic<T> and is_integral_v<T>;

void with_concept(Arithmetic auto){}
void with_concept(Integral auto){}

template<typename T> enable_if_t<is_arithmetic_v<T>> with_sfinae(T){}
template<typename T> enable_if_t<is_arithmetic_v<T> and is_integral_v<T>> with_sfinae(T){}

int main()
{
    with_concept(1);
    with_concept(1.0);
    
    // with_sfinae(1); // error: call of overloaded 'with_sfinae(int)' is ambiguous
    with_sfinae(1.0);
}

LIVE DEMO
enable_if просто добавляет условие на включение или выключение перегрузки, там нет никакого сравнения специфичности условий. Поэтому в случае with_sfinae(1), когда оба условия сработали, получается неоднозначность.
До концепций это например решалось через наследование — смотри реализацию std::advance — там внутри диспатчинг по тэгу итератора, которые вручную частично упорядоченны наследованием, либо например жёстко заданным порядком
Автор: jazzer
Дата: 02.03.10
, либо опять таки можно ввести упорядоченность через if constexpr.
Отредактировано 03.10.2020 3:37 Evgeny.Panasyuk . Предыдущая версия . Еще …
Отредактировано 03.10.2020 3:34 Evgeny.Panasyuk . Предыдущая версия .
Отредактировано 03.10.2020 3:28 Evgeny.Panasyuk . Предыдущая версия .
Re[7]: Зачем нужны concept?
От: Videoman Россия https://hts.tv/
Дата: 03.10.20 08:34
Оценка:
Здравствуйте, Evgeny.Panasyuk, Вы писали:

EP>Ниже пример где уже видно частичное упорядочивание, и без дополнительных трюков на голом enable_if не получится:

EP>
EP>#include <type_traits>
EP>using namespace std;

EP>template<typename T> concept Arithmetic = is_arithmetic_v<T>;
EP>template<typename T> concept Integral = Arithmetic<T> and is_integral_v<T>;

EP>void with_concept(Arithmetic auto){}
EP>void with_concept(Integral auto){}

EP>template<typename T> enable_if_t<is_arithmetic_v<T>> with_sfinae(T){}
EP>template<typename T> enable_if_t<is_arithmetic_v<T> and is_integral_v<T>> with_sfinae(T){}

EP>int main()
EP>{
EP>    with_concept(1);
EP>    with_concept(1.0);
    
EP>    // with_sfinae(1); // error: call of overloaded 'with_sfinae(int)' is ambiguous
EP>    with_sfinae(1.0);
EP>}
EP>

EP>LIVE DEMO
EP>enable_if просто добавляет условие на включение или выключение перегрузки, там нет никакого сравнения специфичности условий. Поэтому в случае with_sfinae(1), когда оба условия сработали, получается неоднозначность.

Да, интересное замечание. Действительно полезное свойство.

EP>До концепций это например решалось через наследование — смотри реализацию std::advance — там внутри диспатчинг по тэгу итератора, которые вручную частично упорядоченны наследованием, либо например жёстко заданным порядком
Автор: jazzer
Дата: 02.03.10
, либо опять таки можно ввести упорядоченность через if constexpr.


Достаточно просто убрать неоднозначность, правда на практике это бывает сложно сделать:
Re[8]: Зачем нужны concept?
От: Evgeny.Panasyuk Россия  
Дата: 03.10.20 09:31
Оценка:
Здравствуйте, Videoman, Вы писали:

EP>>До концепций это например решалось через наследование — смотри реализацию std::advance — там внутри диспатчинг по тэгу итератора, которые вручную частично упорядоченны наследованием, либо например жёстко заданным порядком
Автор: jazzer
Дата: 02.03.10
, либо опять таки можно ввести упорядоченность через if constexpr.

V>Достаточно просто убрать неоднозначность, правда на практике это бывает сложно сделать:

Здесь структура намного сложней — условие enable_if каждой перегрузки зависит от всех других, потому что конечные условия должны быть взаимоисключающими. Например попробуй добавить ещё предикаты is_fundamental и is_unsigned.
Если пытаться без концепций, то всё же if constexpr намного удобнее и лаконичней (конечно там где можно вместо перегрузок использовать один шаблон функции со статическими ветвлениями), так как там можно добавлять else if не дублируя остальные условия, можно делать вложенные ветвления и т.п.
Re: Зачем нужны concept?
От: x-code  
Дата: 05.10.20 18:51
Оценка:
Здравствуйте, PavelCH, Вы писали:

PCH>Пытаюсь понять зачем нужны а с++ концепты. Ну первое что лежит на поверхности это избегание ошибок на этапе генерации. А что ещё? Как практически применять эту штуку? Для чего комитет заседал столько времени? Почему они должны "спасти мир"? Что такого без них нельзя было делать а с ними можно?


Наконец-то ввели в шаблоны статическую типизацию или каклй-то ее аналог.
А статическая типизация это всегда хорошо.
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.