Когда смотришь на то, что предполагается в Concepts Light в C++, то аппетитно облизываешься на возможность перегрузки шаблонных функций по именам концептов как по типам. Например, функция записи в данных в поток могла бы иметь следующие перегрузки:
void write(std::ostream& out, const DirectWritable& val); void write(std::ostream& out, const Reflectable& val);
для типов которые можно записать используюя operator<< (DirectWritable) и типов которые разметили используюя технику описанную в предыдущем моём посте (Reflectable). Можно ли получить такой же функционал без компилятора который бы поддерживал Concepts Light (на данный момент оный TS поддержан только в ветке по разработке gcc 6 релиз из которой ожидается вроде этой весной)?
Ответ, да можно! Но только отчасти. Сегодня для таких перегрузок используется SFINAE и выглядит это страшно:
template<typename T> void write( std::ostream& out, const typename std::enable_if< is_direct_writable<T>::value, T>::type& val );
Но если приглядеться внимательно, то можно заметить, что второй параметр очень похож на то, что хочется получить. А начит можно записать его вот так:
template<typename T> using DirectWritable = typename std::enable_if< is_direct_writable<T>::value, T >::type; template<typename T> void write(std::ostream& out, const DirectWritable<T>& val);
Правда тут вылазит то самое слово "отчасти", что я употребил чуть выше. Дело в том, что такой подход убивает самую важную фичу шаблонных функций: вывод параметров шаблона из типов аргументов. И, несомненно, упущенным оказывается важный момент идеи концептов: красивые и понятные сообщения об ошибках. Чтобы устранить эти недостатки, надо выплонить "закат солнца вручную", а имнно унести такие перегрузки в условно приватное пространство имён detail (такое имя используется в реализации стандартной библиотеки поставляемой с gcc для сокрытия деталей реализации) и завести шаблонную функу, которая будет выводить параметры и генерировать красивые сообщения об ошибках:
template<typename T> void write(std::ostream& out, const T& val) { static_assert( is_direct_writable<T>::value || is_reflectable<T>::value, "val argument must satisfy one of the following concepts: DirectWritable, Reflectable" ); detail::write<T>(out, val); }
На самом деле преимуществ от такого подхода к сокрытию SFINAE достаточно, чтобы не лениться и писать подобные мусорные функции-обёртки при работе с обобщённым кодом сегодя в ожидании того светлого завтра, когда у нас будут Concepts Lite.
Комментариев нет:
Отправить комментарий