Так как я обнаружил CRTP
несколько лет назад я использовал его во многих местах для достижения полиморфизма во время компиляции для очень интенсивных вычислительно-ориентированных кодов. Замечательно «впрыскивать» функции-члены в классы универсальным способом, когда нужно заботиться как об универсальности, так и о максимальной производительности во время выполнения.
Я прочитал / посмотрел несколько вещей на concepts lite
которая будет (я надеюсь) частью следующего C++
стандарт. Будет совершенно удивительно проектировать функции в более абстрактной и обобщенной манере, избегая ужасных линий SFINAE/std::enable_if
Я сейчас пользуюсь.
Я не проверял g++
ветви, которые реализуют концепции, чтобы поиграть с ними и исследовать методы метапрограммирования, которые мне нравятся по-новому. Но, возможно, некоторые из вас имеют. Сначала я подумал, что концепции не решат проблему статического полиморфизма, но так как подобные вещи могут сильно зависеть от уловок, я могу ошибаться. Итак, мой вопрос заключается в следующем: Смогут ли концепты Lite достичь полиморфизма во время компиляции (как мы можем сделать через CRTP
) более удобным способом? (примеры кода приветствуются).
Я не должен так думать. Concepts Lite заменит ваше использование enable_if
, но я не уверен, что это учитывает новые методы для CRTP. С другой стороны, могут быть некоторые интересные вещи, которые можно сделать.
Я скажу, что столкнулся с некоторыми проблемами CRTP при более ранней реализации концепций lite. Проверка ограничений требует, чтобы аргументы типа были полные типы. Если у вас есть базовый класс, параметризованный над производным классом, вам нужно отложить проверку до точки использования. Например:
template<Fooable D>
struct crtp {
void f() {
static_cast<D*>(this)->g();
}
};
struct derived : crtp<derived> { // Error!
};
Когда вы пытаетесь проверить Fooable<derived>
, производное еще не определено. Лучше написать так:
template<typename D>
struct crtp {
void f() requires Fooable<D>() {
static_cast<D*>(this)->g();
}
};
Сейчас, Fooable<D>()
проверяется только когда f()
называется.
Просто к вашему сведению.
Поэтому мой вопрос заключается в следующем: смогут ли понятия облегчить полиморфизм во время компиляции (как мы в настоящее время можем сделать с помощью CRTP) более удобным способом? (примеры кода приветствуются).
Нет — они не будут подавлять CRTP
в общем. Понятия lite в основном касаются простоты перегрузки и определения универсальных функций, а также простоты синтаксических проверок:
template<typename T>
concept bool EqualityComparable()
{
return requires(T a, T b)
{
bool = {a == b};
bool = {a != b};
};
}
template<InputIterator I, EqualityComparable T>
I find(I first, I last, T x);
// or
template<InputIterator I>
I find(I first, I last, EqualityComparable x);
Я думаю, что концепции Lite будет подавлять многие случаи использования std::enable_if
,
CRTP
имеет разные варианты использования, некоторые из них действительно связаны с перегрузкой, например:
template<typename Derived>
void do_something(const CRTP_Base<Derived> &x);
Но CRTP
не ограничивается перегрузкой, у него есть другие приложения: например, основной вариант использования для std::enable_shared_from_this
не подразумевает никакой перегрузки:
class Widget : std::enable_shared_from_this<Widget>
{
// ...
};
Некоторые из случаев использования CRTP
задействовать даже виртуальные функции — например, автоматическую реализацию Cloneable
интерфейс:
// Simple example, no covariance, etc
struct Base
{
typedef unique_ptr<Base> Unique;
virtual Unique clone() const = 0;
virtual ~Base() = default;
};
template<typename Derived>
struct ImplementCloneable: protected Base
{
Unique clone() const override
{
return Unique(new Derived(static_cast<const Derived&>(*this)));
}
protected:
~ImplementCloneable() = default;
};
struct Widget: ImplementCloneable<Widget>
{
};
Насколько я понимаю, должна быть возможность использовать Concepts Lite для определения своего рода «статического интерфейса», который говорит о том, что Концепция требует, чтобы определенные функции-члены существовали в классе и могли вызываться с помощью определенных сигнатур. Похоже, что это может быть полезно для статического полиморфизма в некоторых ситуациях.
Однако я не думаю, что это действительно предполагаемое использование для Concepts Lite. В выступлениях, которые я видел, кажется, предположили, что должно быть относительно немного Концепций, и они должны быть довольно фундаментальными (думает как концепция «прямого итератора»), а не использоваться для определения специальных статических интерфейсов.