1

I have been developing a library for a while and now that I think it's ready, I am trying to follow the pimpl principle in order to hide implementation details.

// File Class.h
class Class {
public:
  Class();

private:
    class ClassImpl;
    ClassImpl* rep;
};

// File Class.cpp
#include "Class.h"
#include "ClassImpl.h"
Class::Class() {
    rep = new ClassImpl();
}

The implementation class is defined in another file as follow

// File ClassImpl.h
#include "Class.h"
class Class::ClassImpl {
public:
  ClassImpl();
};

And its implementation:

// File ClassImpl.cpp
#include "ClassImpl.h"
#include <iostream>

using C = Class::ClassImpl; // error: 'class Class::ClassImpl' is private
C::ClassImpl() {
  std::cout << "Implementation constructor";
}

Main function:

// File main.cpp
#include "Class.h"
int main() {
    Class c;
    return 0;
}

Doing this, the compiler says error: 'class Class::ClassImpl' is private on the using line in ClassImpl.cpp. If I remove it and use Class::ClassImpl instead, everything works fine.

Is there a way to use usingon the private nested class ClassImpl ?

YSC
  • 38,212
  • 9
  • 96
  • 149
Xatyrian
  • 1,364
  • 8
  • 26
  • Does the example at the end of the page, that you refer to, do the same thing as you? Do they also try to use `using` and the `impl` of the `widget` class in the `main()` function? No. – Duck Dodgers Jan 02 '19 at 11:31
  • @JoeyMallone no because they define the function inside the class declaration. It seems a good idea in the example page but because my implementation is hundred-of-line-long, then it is not adequate to me – Xatyrian Jan 02 '19 at 11:35
  • try this `ClassImpl::ClassImpl() {` for the constructor and leave `using`. – Duck Dodgers Jan 02 '19 at 11:37
  • I have nothing to back up this claim (hence only as a comment), but no, it is not possible. You are trying to create an [alias](https://en.cppreference.com/w/cpp/language/type_alias). Imagine if you could create an alias to any private symbol. That would break the entire purpose of access modifiers, wouldn't it? Anyhow, although I hate the precompiler, you can achieve the same code reduction by simply defining a constant: `#define C Class::ClassImpl` – Kiruse Jan 02 '19 at 11:38

2 Answers2

1

Is there a way to use usingon the private nested class ClassImpl ?

Yes. Declare ClassImpl with public access in Class:

class Class {
public:
    Class();
    class ClassImpl;

private:
    ClassImpl* rep; // should be reference, see note.
};

// ...

using C = Class::ClassImpl;

Live demo

You can also make ClassImpl not a nested class.

Note: you might prefer having Class::rep to be a reference rather than a (naked) pointer. There is no reason for a valid Class instance not to have an implementation object (a null pointer).

YSC
  • 38,212
  • 9
  • 96
  • 149
1

Is there a way to use using on the private nested class ClassImpl?

The short answer is "no".

Longer answer follows.

What you're trying to do is a using declaration, not a using directive.

Your using declaration

using C = Class::ClassImpl;

is at file scope, so the name Class::ClassImpl cannot be used directly as a name in that scope.

The first relevant section of the standard (C++17) is Section 10.3.3 "The using declaration", for which para 19 states "A synonym created by a using-declaration has the usual accessibility for a member-declaration".

To find what is meant by "usual accessibility", refer to Section 14 "Member Access Control", which states that "private names can only be used by members and friends of the class in which it is declared". The usage of "names" here is quite specific - anything with a name that is private to a class (member declarations, type declarations, etc) are treated the same way.

If you want to have a using declaration at file scope, as per your example;

using C = Class::ClassImpl;

then ClassImpl needs to be a public name (of a nested class) of Class. private and protected names of a class cannot be accessed at file scope.

Peter
  • 35,646
  • 4
  • 32
  • 74