2

在了解嵌套类是嵌套类的成员并因此可以完全访问嵌套类的成员这一事实之后(至少对于 C++11,请参见此处),我在尝试创建嵌套类模板时遇到了一个问题:

#include <iostream>

using namespace std;

// #define FORWARD 

class A {

// public: // if FooBar is public, the forward declared version works
protected:
  enum class FooBar { // line 11, mentioned in the error message
    foo,
    bar
  };

protected:
#ifdef FORWARD
  // forward declaration only
  template< FooBar fb = FooBar::foo >
  struct B; 
#else
  // declaration and definition inline
  template< FooBar fb = FooBar::foo >
  struct B{
    void print(){ cout << A::i << (fb==FooBar::foo ? " foo" : " not foo") << endl;};
  };
#endif

public:
  B<>* f;
  B<FooBar::bar>* b;
private:
  static const int i = 42;
}; 

#ifdef FORWARD
// definition of forward declared struct
template< A::FooBar fb>
struct A::B{
  void print(){ cout << A::i << (fb==FooBar::foo ? " foo" : " not foo") << endl; };
}; // line 41, mentioned in the error message
#endif


int main(int argc, char **argv)
{
  A a;
  a.f->print();
  a.b->print();
  return 0;
}

这应该(并且确实)输出:

42 foo
42 not foo

问题

#define FORWARD如果未注释,即已FORWARD定义,为什么这段代码不编译?

我得到的错误(来自 gcc 4.7.2)是

main.cpp:11:14: error: ‘enum A::FooBar’ is protected
main.cpp:41:2: error: within this context

从对早期问题的回答中,我了解到它是它的成员,并且应该可以访问它的(私人)成员(它确实如此,它会打印)。那么为什么不能在类外声明中访问呢?BAA::iA::FooBar

背景

对于标头和实现分离的其他一些代码,这显然是一个最小的示例。我本来希望只转发声明嵌套类模板B以使类的接口A更具可读性,因为那时我可以将模板类的实现推到头文件的末尾(即一个人会得到的行为/设置通过取消注释#define FORWARD)。所以是的,这是一个相当美观的问题——但我相信这表明我不明白发生了什么,因此我很想了解这个问题,但为什么呢?.

4

1 回答 1

5

您可以将示例简化为:

class A
{
private:
  enum FooBar { foo };

public:
  template< FooBar fb = foo >
  struct B;
};

template< A::FooBar >
struct A::B
{
};

A::B<> a;

正如DR 580所阐明的那样,这是合法的,并且被 Clang++ 接受,所以看起来 G++ 还没有实现该解决方案。

我已将此报告为GCC PR 56248并且还报告了 Clang PR 15209,因为 Clang 也没有完全实现 DR 580。

于 2013-02-07T23:25:41.150 回答