шаблон, который обеспечивает интерфейс - PullRequest
3 голосов
/ 11 октября 2009

Можно ли создать шаблон, принимающий типы, которые реализуют определенный интерфейс? Например, я хочу сказать пользователю шаблона: вы можете хранить что угодно в моем контейнере, если он реализует методы Init() и Destroy().

Спасибо

Ответы [ 7 ]

6 голосов
/ 11 октября 2009

Ограниченное подмножество (предполагаемых, но, к сожалению, ограниченных) функциональных возможностей концепций C ++ 0x обеспечивается библиотекой Boost Concept Check . Вы можете использовать его, создав класс проверки концепции для требуемого интерфейса.

2 голосов
/ 11 октября 2009

Во-первых, если вам требуется существование Init и Destroy, это означает, что код шаблона использует их где-то. Это означает, что их существование уже проверено компилятором, так как шаблон не скомпилируется, если тип не имеет этих методов.

Однако, если вы хотите проверить их, одним из способов может быть использование их адресов в некотором контексте времени компиляции, например,

template <class T>
class X
{
private:
    template <unsigned N>
    struct Number {};
    Number<sizeof(&T::Init) + sizeof(&T::Destroy)> must_define_init_and_destroy();
};

struct A
{
    bool Init();
    void Destroy();
};

struct B {};

int main()
{
    X<A>();
    X<B>();
}

С Comeau вывод:

"ComeauTest.c", line 7: error: class "B" has no member "Init"
          Number<sizeof(&T::Init) + sizeof(&T::Destroy)> must_define_init_and_destroy();
                            ^
          detected during instantiation of class "X<T> [with T=B]" at line 21

"ComeauTest.c", line 7: error: class "B" has no member "Destroy"
          Number<sizeof(&T::Init) + sizeof(&T::Destroy)> must_define_init_and_destroy();
                                               ^
          detected during instantiation of class "X<T> [with T=B]" at line 21

Однако, это ломается, если любой из требуемых методов перегружен, и естественно, что это все еще не проверяет, есть ли у этих методов подходящий прототип.

Например, вы ожидаете, что bool Init (int, int). Вы можете использовать static_cast для проверки точной подписи, но опять же это может наложить ненужные ограничения на тип. Например, что, если в каком-то классе вместо этого установлен bool Init (long, long)?

Так или иначе, эти усилия кажутся необходимыми только для того, чтобы сообщения об ошибках стали более очевидными. Однако я очень сомневаюсь, что любое сообщение, которое вы получите в противном случае без каких-либо концептуальных проверок (например, «нет подходящего метода Init, который вызывается с T = X при использовании здесь») - это плохо.

1 голос
/ 11 октября 2009

Нет, это невозможно.

Шаблоны заменяются на один тип, но не со многими отличиями.

Подумайте о создании базового класса, от которого должны наследоваться все возможные члены, и пропустите все шаблоны.

В основном вы вводите экзистенциальные типы , которые не поддерживаются в C ++.

0 голосов
/ 11 октября 2009

На самом деле все наоборот: если вашему шаблону требуются Init() и Destroy(), его невозможно создать экземпляром для любого типа, который не имеет эти два.

Единственная проблема с шаблонами в этом отношении заключается в том, что требование является неявным (т. Е. Шаблон не будет компилироваться в точке, которая требуется в шаблоне), а не явным (т. Е. Компилятор сообщает вам, что отсутствует в точке инстанции). Концепции должны были это исправить, но они были исключены из следующего стандарта некоторое время назад.

0 голосов
/ 11 октября 2009

Да, вы можете.

Это, однако, довольно сложно (расширенные шаблоны метапрограммирования) Вся концепция построена на качестве «Ошибка замены не является ошибкой (SFINAE)» в шаблонах C ++.

По сути, вы можете создать шаблон, используя что-то вроде 'template <typename T, void (T::*)()>' и создать экземпляр, используя <T, T::Init> в вашем векторе. Если подстановка не существует, вы получите ошибку подстановки (здесь используется принцип SFINAE, потому что в большинстве случаев вы хотели бы использовать конструктор).

Это, конечно, и упрощенное описание. Я сожалею, что в настоящее время не могу предоставить лучшую, но вы можете взглянуть на это обсуждение . найдите has_member и is_call_possible.

Надеюсь, это поможет.
Орен

0 голосов
/ 11 октября 2009

Ну, я думаю, вы могли бы определить метод, который вызывает Init() и Destroy() в аргументе шаблона, и каким-то образом вызвать этот метод в режиме отладки.

Кроме того, вы можете определить интерфейс и привести его к реализации вашего шаблона. Это также может быть отключено в режиме выпуска.

0 голосов
/ 11 октября 2009

Не возможно в текущем стандарте. Я полагаю, что это возможно благодаря «концепциям», которые (?) Должны стать стандартом в C ++ 0x.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...