I want to define a member C++ class template in namespace context. The member class template and the type used by the parameter for that template are declared private in the class that contains the member template. The compiler complains because the type of the template parameter is declared private.

When I use g++ (GCC) 13.2.0 to compile the following code in file temp.cc

// the following class definition would go in its own header file
class A {
public: // I don't want to declare struct S public
private:
  struct N;
  template<const N* K> struct S; // I don't want to define struct S here!
};
// the following definition would go in a separate file
template<const A::N* K> struct A::S {
};

I get the following error

g++ temp.cc
temp.cc:9:19: error: ‘struct A::N’ is private within this context
    9 | template<const A::N* K> struct A::S {
      |                   ^
temp.cc:5:10: note: declared private here
    5 |   struct N;
      |          ^                                                              

Is there a way to appease the compiler without declaring struct N public?

Note that defining struct N in the private scope of class A compiles just fine

class A {
public:
private:
  struct N;
  template<const N* K> struct S {}; // no compilation error!
};

Therefore, the problem is that the compiler behavior seems to be inconsistent: struct A::S is allowed to use struct N* as a template parameter when struct A::S is defined in class A's scope, but not when it is defined in namespace scope. Why not?

3

There are 3 best solutions below

2
On

First things first, when defining the struct S outside, you have not qualified it with the enclosing class. To solve this just add A:: so that S is qualified with the enclosing class.


This seems to be a gcc bug. Both clang and msvc accepts the program.

GCC rejects out of class definition of inner private class template

class A {
    
        struct N;
        
        template<const N* K> struct S; 
};
// works now

class A::N{};
template<const A::N* K> class  A::S{};//gcc rejects this but clang and msbc accepts this 
0
On

In the code you gave, you are declaring a new struct called S outside of A. To indicate that you are defining the private struct within A and not a new struct, you need to change template<const A::N* K> struct S {}; to template<const A::N* K> struct A::S {}; (note the A:: being added).

0
On

Define S in another file, you may hit a link error. I think you can use a proxy pattern, exposing API publicly and hiding data structures internally. Given your example, all code could be:

inA.h file(public header)

class A {
 public:
  Foos();
 private:
  A();
};

A *MakeA();

in A_Proxy.h (internal header)

include 'A.h'
class AProxy : public A {
private:
  struct N;
  template<const N* K> struct S{}; // decl the S here
};
A *MakeA() {
  return new AProxy();
}