Подтип класса доступа через объект

class Foo{

public:
    struct Bar{};

};

...

Foo foo;

foo.Bar bar; //error

Мой компилятор сообщает о недопустимом использовании struct Foo::Bar. Здесь, конечно, я могу назвать подкласс Foo::Bar, если захочу, но если foo имеет очень длинный тип вложенного шаблона и / или был создан с помощью auto, тогда было бы удобно получить доступ к подтипам через объект, подобный этому.

* Edit: Для ясности, я хочу создать объект типа Foo :: Bar без необходимости писать Foo::.

Foo::Bar bar объявляет внутреннюю структуру.
macroland 10.09.2018 07:12
0
1
116
4

Ответы 4

if foo has a very long nested-template type and/or was created with auto then it would be convenient to access subtypes via object like this.

Вы можете использовать следующую стратегию.

  1. Объявите функцию-член, возвращающую тип. Нет необходимости определять его, если он не полезен в противном случае.

  2. Используйте decltype, чтобы компилятор мог унаследовать тип от функции-члена.


Вот обновленная версия вашего опубликованного кода.

class Foo {

   public:
      struct Bar{};

      // Just the declaration is sufficient.
      Bar b() const;

};


int main()
{
   Foo foo;
   decltype(foo.b()) bar;
}

Но функция должна быть const, чтобы шаблон можно было применить и к экземплярам constFoo ...

Aconcagua 10.09.2018 07:40

Если у вас есть член struct Bar внутри class Foo, вы можете использовать decltype:

class Foo{
public:
    struct Bar{};
    Bar f_bar; 

};

Foo foo;
decltype(foo.f_bar) bar;

Следуя аналогичным предыдущим ответам с использованием спецификатор decltype:

class Foo{

public:
    struct Bar{};

};

int main() {
    Foo foo;
    decltype(foo)::Bar bar;
    const Foor foofoo;
    decltype(foofoo)::Bar barbar;
}

Обновлено: включая решение для ссылок или указателей

#include <type_traits>
...

void fref(const Foo &foo) {
   typename std::remove_reference<decltype(foo)>::type::Bar bar;
}

void fpointer(Foo *foo) {
   typename std::remove_reference<decltype(*foo)>::type::Bar bar;
}

Мне нужно удалить ссылку и удалить константу вокруг decltype?

AdyAdy 10.09.2018 07:25

@AdyAdy Работает для констант, не работает для ссылок или указателей.

jsantander 10.09.2018 07:30

Для C++ 17 просто напишите std::remove_reference_t<decltype(foo)>::Bar. Вы также можете сделать std::decay_t<decltype(foo)>::Bar

Justin 10.09.2018 07:53

@Justin Спасибо! Раньше я пытался использовать что-то подобное, я написал макрос для std::remove_reference_t<decltype(foo)>::Bar, но у него были проблемы с typename с типами шаблонов, поэтому использовать его было неудобно

AdyAdy 10.09.2018 08:55

[...] but if [F]oo has a very long nested-template type [...]

Хорошо, если у вас есть:

class Foo
{
    template <typename T>
    class SomeVeryLongAndInconvenientName;
};

вы можете определить псевдоним для определенного типа:

using ShorterName = Foo::SomeVeryLongAndInconvenientName<SomeType>;

или как шаблон:

template <typename T>
using ShorterName = Foo::SomeVeryLongAndInconvenientName<T>;

Другие вопросы по теме