crtp и видимость типов

У меня есть головоломка, которую я пытаюсь решить, и в основном она сводится к следующему примеру:

template <typename CT>
struct A
{
  typedef typename CT::VALUE_T FOO; // FOO is dependent on CT
};

template <typename CT>
struct B
{
  typedef typename CT::BAR BAR;

  BAR foo() {}
};

template <typename DT>
struct C : B<C<DT> >
{
  typedef DT VALUE_T;

  typedef typename A<C>::FOO BAR;
};

int main () {
  C<int> c;
}

Я могу попытаться объяснить вышесказанное (я пытался около трех раз и удалил текст! ), но в основном требования таковы:

  1. C должен наследоваться от B, типизированного с C (эксплуатируя CRTP), т.е. B>
  2. C - единственный, кто может инстанцировать A (i.e. A должен быть типизирован с C)
  3. A - единственный, кто может определить FOO (FOO зависит от типа CT, отношения более сложные, чем представленные)

Проблема (как видно из приведенного выше кода) в том, что тип BAR доступен только внутри C, и он неполный, когда инстанцируется B, поэтому B не видит тип BAR аргумента шаблона CT (C). К сожалению, внутри B тип BAR используется как аргументы функций и возвращаемые типы (т.е. не ограничивается областью видимости функции - в результате я не могу просто перенести typedef в область видимости функции).

Есть ли способ обойти это? Я не могу нарушить указанные выше отношения (разве что в крайнем случае). Предположительно, в c++11 я мог бы использовать auto и обойти необходимость иметь BAR typedef в B, однако в настоящее время такой возможности нет.

EDIT: в продолжение комментария @bitmasks, немного дополнительной информации.

  1. Код в A и B используется во многих двоичных файлах в различных ситуациях, единственная уникальная ситуация в этом случае заключается в том, что C происходит от B, в других случаях C принадлежит экземпляру чего-то, полученного от B.
  2. Аргументы шаблона могут быть изменены (в A и B), при условии, что они могут быть установлены по умолчанию в значения, что не требует изменения существующих применений A и B. Тот же набор типов должен быть доступен либо как параметр шаблона, который задается по умолчанию, либо каким-то другим механизмом.

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

Описания компонентов:

  • A лучше всего описывается как контейнер, а FOO действительно является итератором, то, что он содержит, определяется типизацией параметра шаблона
  • B лучше всего описывается как базовый класс, который содержит набор функций, вызываемых некоторыми компонентами принадлежащими экземпляру C. В предыдущих случаях этим компонентам передавалась ссылка на вещи, производные от B (и эти вещи также принадлежат C), в данном случае я предоставляю ссылку на сам C.

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

6
задан Nim 6 December 2011 в 16:32
поделиться