1

Background

I have a private data structure buried within many nested namespaces & classes as shown in the (simplified) example below. The private structure contains numerous static const members (lengthy STL containers, mostly), represented in this example by a single static const int i.

Note: the presence of the const here doesn't seem to bear on my problem; it's included merely for the sake of completeness.

#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;
}


Need

Defining static members such as i outside of their data structure is trivial (see [A]). However, as the number of namespaces/classes/structs in a member's hierarchy grows, it becomes desirable to abbreviate the hierarchy (chain/tree/prefix?) in the member's definition for the sake of readability. Imagine something like the following was required, many times over:

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

At some point, for the coder's sanity, they would want to shorten the syntax of this operation.


Problem

My naive attempt (see [B]) at aliasing the definition of i via the using directive has not worked as expected due to the Data structure being private. Swapping code block [B] for [A] yields (in VS2017):

error C2248: 'foo::bar::MyClass::Data': cannot access private struct declared in class 'foo::bar::MyClass'

Ideone (gcc?) results in a similar error at [B]:

error: ‘struct foo::bar::MyClass::Data’ is private within this context


Question(s)

  1. Why doesn't [B] work, while [A] does?
  2. How might I define i with its hierarchy chain/tree/prefix aliased (preferably via using)?
  3. Bonus: What is the preferred nomenclature for what I've been calling the namespace/class/structure hierarchy chain/tree/prefix when referencing a member?

Other questions (such as using alias for static member functions?) hew closely to mine, but don't seem to pertain.

Please feel free to improve this question with any edits or suggestions.

1 Answers1

1

Why doesn't [B] work, while [A] does?

private stuff (class/member name) can only be used at several places, including definitions (which is [A]) but not aliases (in scope not allowed to use types)

How might I define i with its hierarchy chain/tree/prefix aliased (preferably via using)? Bonus: What is the preferred nomenclature for what I've been calling the namespace/class/structure hierarchy chain/tree/prefix when referencing a member?

You might still shorten the namespace part:

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

And for the class part, you can still add some using in parent class, if acceptable:

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:
    // ...
};

And finally:

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

becomes:

using namespace foo::bar::baz;

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

Demo

Jarod42
  • 203,559
  • 14
  • 181
  • 302
  • I like the approach of `using inner =` within the class structure (nice!), however that alias is itself `private` & thus results in the same errors. Making that `inner` alias `public` seems to work, but does that expose my private parts? – quasinormalized Apr 05 '19 at 23:31
  • @quasinormalized: Demo added. `inner` might (and should, to keep initial intend) be private. but indeed, whole path should be accessible for `MyClass` to construct the alias. – Jarod42 Apr 05 '19 at 23:45
  • I see how this is the answer to what, I now realize, was my overly reductive question. In my attempt to simplify my problem for SO, I omitted the fact that there was a PIMPL amongst my privates. E.g.: `MyClass` would be the interface and `MySubClass` the PIMPL'd implementation. Hence, `using inner = MySubClass::…` complains about `MySubClass` being an incomplete type. Any further insight you (or anyone) has would be most welcome; otherwise, I'll accept this answer & just live with my unsightly, long definitions. Any ideas? I can make that a new question if appropriate. – quasinormalized Apr 08 '19 at 16:56
  • So you might do the `inner` from the pimpl class. Which reduces length less than from main class (a at definition place, you will have definition of full classes). – Jarod42 Apr 08 '19 at 22:58