У меня есть головоломка, которую я пытаюсь решить, и в основном она сводится к следующему примеру:
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;
}
Я могу попытаться объяснить вышесказанное (я пытался около трех раз и удалил текст! ), но в основном требования таковы:
C
должен наследоваться от B
, типизированного с C
(эксплуатируя CRTP), т.е. B>
C
- единственный, кто может инстанцировать A
(i.e. A
должен быть типизирован с C
)A
- единственный, кто может определить FOO
(FOO
зависит от типа CT
, отношения более сложные, чем представленные)Проблема (как видно из приведенного выше кода) в том, что тип BAR
доступен только внутри C
, и он неполный, когда инстанцируется B
, поэтому B
не видит тип BAR
аргумента шаблона CT
(C
). К сожалению, внутри B
тип BAR
используется как аргументы функций и возвращаемые типы (т.е. не ограничивается областью видимости функции - в результате я не могу просто перенести typedef в область видимости функции).
Есть ли способ обойти это? Я не могу нарушить указанные выше отношения (разве что в крайнем случае). Предположительно, в c++11 я мог бы использовать auto
и обойти необходимость иметь BAR
typedef в B
, однако в настоящее время такой возможности нет.
EDIT: в продолжение комментария @bitmasks, немного дополнительной информации.
A
и B
используется во многих двоичных файлах в различных ситуациях, единственная уникальная ситуация в этом случае заключается в том, что C
происходит от B
, в других случаях C
принадлежит экземпляру чего-то, полученного от B
. A
и B
), при условии, что они могут быть установлены по умолчанию в значения, что не требует изменения существующих применений A
и B
. Тот же набор типов должен быть доступен либо как параметр шаблона, который задается по умолчанию, либо каким-то другим механизмом. Я использую шаблоны здесь просто потому, что мне нужна тесная связь, и мне нужна гибкость, чтобы использовать код в различных ситуациях.
Описания компонентов:
A
лучше всего описывается как контейнер, а FOO
действительно является итератором, то, что он содержит, определяется типизацией параметра шаблонаB
лучше всего описывается как базовый класс, который содержит набор функций, вызываемых некоторыми компонентами принадлежащими экземпляру C
. В предыдущих случаях этим компонентам передавалась ссылка на вещи, производные от B
(и эти вещи также принадлежат C
), в данном случае я предоставляю ссылку на сам C
. Основная сложность возникает при обращении к контейнеру A
, ранее отношения между B
и C
заключались в том, что C
имеет экземпляр от B
, но теперь C
является экземпляром из B
- это изменение семантики нарушает способ введения типов в классы.