在定义之前,可以在模板类中使用类本地类型

时间:2014-02-25 17:19:55

标签: c++ templates

我有一种情况,我有一个模板类,它实际上只暴露一个公共函数,并使用一个本地定义的结构用于内部状态,我不想混淆我的标题的公共部分。例如:

template <class T>
class MyClass {
public:

   struct InternalState {
       // lots of noisy stuff I don't want to see in the public section
   };

   void userCallableFunction() {
      InternalState state;
      doPrivateStuff(state);
   }

 private:
   doPrivateStuff(InternalState& state) {
      // ok for the internals to go here 
   }
 };

我想将InternalState的定义推送到私有部分,因为类的客户端不需要查看它。我想减少噪音,所以看起来像这样:

template <class T>
class MyClass {
public:
   // only the stuff the client needs to see here
   void userCallableFunction() {
      InternalState state;
      doPrivateStuff(state);
   }

 private:
   // fine for the private noise to be down here
   struct InternalState {
   };

    ... 
 };

问题是:这样做是否合法?即在InternalState中使用后声明userCallableFunc() ?我知道你不能为非内联/模板化函数执行此操作,但哪些规则适用于内联/模板函数?

编辑:

我在Visual Studio 2010,Clang 4.1和gcc 4.8.1(IdeOne中的示例,以及非模板但inlined case)中尝试了这一点,并且它为所有人成功构建。所以问题是,这样做是否安全和便携?请提供参考,而不是仅仅说'不,你不能这样做'。

2 个答案:

答案 0 :(得分:1)

作为unqualified-id(no ::)并且不具有可以解释为函数的语法,可以应用ADL,语句中的名称InternalState

InternalState state;
使用正常的非限定查找(查找不受限制的名称)查找

对于成员函数的 body 中的非限定名称,应用特殊规则,请参阅[basic.lookup.unqual] / 8

  

对于类X的成员,成员函数体[...]中使用的名称应以下列方式之一声明:

     
      
  • 在使用它之前或在封闭块(6.3)或
  • 中使用之前   
  • 应该是类X的成员,或者是X(10.2)的基类成员,或者
  •   

请注意,这会对非限定查找施加排序:首先,搜索封闭块,然后,如果未找到任何内容,则搜索类成员。另请注意:由于此上下文中的InternalState不依赖于模板参数,因此不会搜索基类范围(如果存在基类)。

重要的是有点微妙,不幸的是:应该是班级成员X 暗示应在成员之前宣布功能体。例如,

struct X
{
    int meow()
    {
        return m; // (A)
    }

    int m;
} // (B)
;

在行(A)中,在当前块中找不到名称m(或任何封闭块,块是复合语句,而不是任何{})。因此,它会在X整个成员集中查找。只有在X完成后,即(B)

,才能进行此操作。

这同样适用于引用嵌套类的名称 - 毕竟,名称查找需要找出名称所指的实体的类型(例如函数,变量,类型)。此外,查找非详细名称IIRC并不区分这些类型。

不幸的是,这是我现在能找到的最好的:/我不高兴,因为它非常微妙,只能间接回答这个问题。

答案 1 :(得分:0)

您只能转发声明InternalState,然后在编译器看到定义之前使用指针或引用:

template <class T>
class MyClass {
public:
   // only the stuff the client needs to see here
   void userCallableFunction() {
      std::unique_ptr<InternalState> state = createInternal();
      doPrivateStuff(*state);
   }

 private:
   void doPrivateStuff(InternalState const&);

   // fine for the private noise to be down here
   struct InternalState {
   };

   std::unique_ptr<InternalState> createInternal() {
       return std::make_unique<InternalState>();
   }

 };

它类似于PIMPL惯用法,所以你可能想要查看它。