CRTP - «абстрактный» метод в статическом интерфейсе - PullRequest
0 голосов
/ 10 января 2019

Я пытаюсь найти способ принудительно заключить договор между базовым классом CRTP и производным. При использовании динамического полиморфизма можно просто сделать:

struct foo{
    virtual bar() = 0;
};

И компилятор позаботится о том, чтобы метод bar был реализован в производном классе, в противном случае он выдаст (более или менее) значимое сообщение об ошибке. Теперь лучшее, что я мог получить с помощью CRTP - это что-то вроде этого:

template<class Derived>
struct base {
    void stuff(){
        static_cast<Derived &>(*this).baz();  
    }
};

Который каким-то образом обеспечит реализацию baz в производном классе, но на самом деле не читается и не ясно, каков контракт между базовым и производным классом. Итак, мой вопрос, есть ли способ сделать это лучше? Я знаю о C ++ 20 Concepts и что они были бы идеальным решением для этого случая, но я ищу C ++ 11 / C ++ 14 решение, чтобы сделать его максимально чистым.

1 Ответ

0 голосов
/ 11 января 2019

Поскольку производный класс всегда является неполным, когда определяется база, одно из решений, которое я использую, заключается в том, чтобы отложить создание экземпляра «проверки концепции» с помощью параметра шаблона по умолчанию:

template<class T>
using has_baz = decltype(std::declval<T&>().baz());

template<class Derived>
struct base{
  template<class T = Derived, has_baz<T>* =nullptr>
  void stuff(){/*...*/}
  };

Обратите внимание, что концепции c ++ 20 не решат эту особую проблему, и отсрочка проверки концепции все равно будет необходима. Преимущество состоит в том, что ошибка компиляции будет более понятной.

Демо

...