Как избежать повторения типа окружающего класса, когда нельзя использовать auto и decltype()

Недавно я обнаружил функции auto и decltype() C++11, которые превосходны, поскольку позволяют избавиться от большого количества избыточного кода типов. Однако есть контексты, в которых они не могут быть использованы. Один пример, о котором я в первую очередь спрашиваю, - это если вы хотите объявить переменную, тип которой использует тип окружающего класса, либо напрямую, либо в качестве аргумента шаблона, и у вас нет выражения инициализации (которое позволило бы вам использовать auto). Это особенно нежелательно, если объемлющий тип класса является классом-шаблоном со многими параметрами шаблона. Например:

template<typename T1, typename T2, typename T3, typename T4, typename T5 > struct S {
    std::map<int,S<T1,T2,T3,T4,T5>*> m1;
    std::map<int,S<T1,T2,T3,T4,T5>*> m2;
    std::map<int,S<T1,T2,T3,T4,T5>*> m3;
    std::map<int,S<T1,T2,T3,T4,T5>*> m4;
    std::map<int,S<T1,T2,T3,T4,T5>*> m5;
};

Логичным решением является использование typedef:

template<typename T1, typename T2, typename T3, typename T4, typename T5 > struct S {
    typedef S<T1,T2,T3,T4,T5> ThisClass;
    std::map<int,ThisClass*> m1;
    std::map<int,ThisClass*> m2;
    std::map<int,ThisClass*> m3;
    std::map<int,ThisClass*> m4;
    std::map<int,ThisClass*> m5;
};

Но по-прежнему нежелательно объявлять typedef, который просто повторяет тип окружающего класса.

На самом деле это можно решить, если вы находитесь внутри метода экземпляра, выведя тип *this, хотя необходимый код более подробный, чем хотелось бы:

auto copy(void) {
    typename std::remove_reference<decltype(*this)>::type s = *this;
    // ... do stuff with s ...
    return s;
}

Это решение не работает в области класса, потому что this не разрешено и не имеет смысла вне методов экземпляра (компилятор жалуется "invalid use of ‘this’ at top level").

Итак, мой вопрос: когда вы не можете использовать auto или decltype(), каково рекомендуемое решение, чтобы избежать повторения типа окружающего класса, когда вам нужно использовать его внутри определения класса? Является ли typedef единственным вариантом?


person bgoldst    schedule 08.02.2015    source источник
comment
У меня возникает соблазн сказать, что это фактически дубликат stackoverflow.com/q/21143835/560648. Что мы думаем? В частности, решения там могут не работать, поскольку ваш S здесь является шаблоном класса.   -  person Lightness Races in Orbit    schedule 08.02.2015
comment
Это связанные вопросы, но я бы сказал, что мой вопрос более общий, поскольку я спрашивал о том, как избежать повторения типа класса теоретически любыми средствами (например, выводом типа), а не конкретно о получении псевдонима self, хотя это может быть решением.   -  person bgoldst    schedule 08.02.2015


Ответы (1)


Нет необходимости повторять параметры шаблона, если вы имеете в виду текущий экземпляр.

template<typename T1, typename T2, typename T3, typename T4, typename T5 > struct S {
    std::map<int,S*> m1;
    std::map<int,S*> m2;
    std::map<int,S*> m3;
    std::map<int,S*> m4;
    std::map<int,S*> m5;
};

имя внедренного класса S относится к текущему экземпляру, в данном случае S<T1, T2, T3, T4, T5>.

person Brian Bi    schedule 08.02.2015
comment
Очень красиво, я этого не знал! Это, безусловно, помогает. Но имя класса все равно должно повторяться. Есть ли способ избежать повторения имени класса во всем определении класса? - person bgoldst; 08.02.2015
comment
@bgoldst Я не понимаю твоего вопроса. Вы должны использовать something для ссылки на тип класса — что может быть яснее фактического типа? - person Barry; 08.02.2015
comment
Я подозреваю, что OP хочет что-то вроде self на случай, если имя класса изменится позже. Нет, я почти уверен, что такого рода вещей не существует в C++. Возможно, это будет добавлено, когда С++ получит отражение... - person Brian Bi; 08.02.2015
comment
@ Брайан, правильно, это именно то, что я искал. Думаю, мне придется повторить имя класса, что не так уж и плохо теперь, когда я знаю, что параметры шаблона не нужно повторять. Спасибо! - person bgoldst; 08.02.2015