Псевдоним определение статического члена из частной подструктуры - PullRequest
1 голос
/ 06 апреля 2019

Фон

У меня есть private структура данных, скрытая во многих вложенных пространствах имен и классах, как показано в (упрощенном) примере ниже. Структура private содержит множество static const членов (в основном длинных контейнеров STL), представленных в этом примере одним static const int i.

Примечание: присутствие const здесь, похоже, не влияет на мою проблему; это включено просто ради полноты.

#include <iostream>
using std::cout; using std::endl;

namespace foo {
    namespace bar {
        class MyClass {
            struct Data {
                static const int i;
                // ... + many more
            };
        public:
            int Get() const { return Data::i; }
        };  
    }
}

/////////////////////////////////////////////////////////////////////////////
const int foo::bar::MyClass::Data::i = 42;  // [A] <- Verbose; but works fine
// ... + many more                          // [A]

//using concise = foo::bar::MyClass::Data;  // [B] <- Nope; 'Data' is private
//const int concise::i = 42;                // [B] <- Ideally
//// ... + many more                        // [B]
/////////////////////////////////////////////////////////////////////////////

int main()
{
    cout << foo::bar::MyClass{}.Get() << endl;
    return 0;
}


Потребность

Определение статических элементов, таких как i вне их структуры данных, тривиально (см. [A]). Однако по мере увеличения числа пространств имен / классов / структур в иерархии члена становится желательным сокращать иерархию (цепочка / дерево / префикс ? ) в члене определение ради читабельности . Представьте себе что-то вроде следующего, много раз:

const std::vector<std::string> foo::bar::baz::MyClass::MySubClass::MySubSubClass::PrivateDataStruct::vecOfStr = {…};

В какой-то момент, для здравомыслия кодера, они захотят сократить синтаксис этой операции.


Проблема

Моя наивная попытка (см. [B]) наложить определение i с помощью директивы using не сработала , как ожидалось , поскольку структура Data была private. Замена кода блока [B] для [A] выходов ( в VS2017 ):

ошибка C2248: 'foo :: bar :: MyClass :: Data': невозможно получить доступ к закрытой структуре, объявленной в классе 'foo :: bar :: MyClass'

Ideone (gcc?) Приводит к аналогичной ошибке при [B]:

ошибка: ‘struct foo :: bar :: MyClass :: Data’ является закрытой в этом контексте


Вопрос (ы)

  1. Почему [B] не работает , а [A] работает?
  2. Как мне определить i с псевдонимом цепочки / дерева / префикса иерархии (предпочтительно через using)?
  3. Бонус: Какова предпочтительная номенклатура для того, что я называю цепочкой имен / класса / структуры иерархии / дерева / префикса при обращении к члену?

Другие вопросы (например, использование псевдонима для статических функций-членов? ) тесно связаны с моими, но, похоже, не относятся к ним.

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

1 Ответ

1 голос
/ 06 апреля 2019

Почему [B] не работает, а [A] работает?

private вещи (имя класса / члена) могут использоваться только в нескольких местах, включая определения (это [A]), но не псевдонимы (в области не разрешено использовать типы)

Как я могу определить i с псевдонимом цепочки / дерева / префикса иерархии (желательно через использование)? Бонус: Какова предпочтительная номенклатура для того, что я называю цепочкой имен / класса / структуры иерархии / дерева / префикса при обращении к члену?

Вы можете сократить часть пространства имен:

 using namespace foo::bar;
 const int MyClass::Data::i = 42;

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

class MyClass {
    class MySubClass{
        friend class MyClass;
        class MySubSubClass{
            friend class MyClass;
            class PrivateDataStruct {
                static const std::vector<std::string> vecOfStr;
                // ...
            };
            // ...
        };
        // ...
    };
    using inner = MySubClass::MySubSubClass::PrivateDataStruct;
public:
    // ...
};

И наконец:

const std::vector<std::string>
foo::bar::baz::MyClass::MySubClass::MySubSubClass::PrivateDataStruct::vecOfStr = {/*…*/};

становится:

using namespace foo::bar::baz;

const std::vector<std::string> MyClass::inner::vecOfStr = {/*…*/};

Демо

...