【问题标题】:Inner class depending on a template argument取决于模板参数的内部类
【发布时间】:2011-03-24 13:09:13
【问题描述】:

考虑下一个例子:

#include <iostream>
#include <typeinfo>

template< int N, typename T >
struct B
{
    struct C;
};

template< typename T >
struct B< 0, T >::C
{
    typedef T type;
};

template< int N, typename T >
struct B< N, T >::C
{
    typedef T type[N];
};

int main()
{
    std::cout<<"n=0   type = " << typeid( B< 0, float >::C::type ).name() << std::endl;
    std::cout<<"n=5   type = " << typeid( B< 5, float >::C::type ).name() << std::endl;
}

使用 g++(4.3.0 版)编译时

g++ dfg.cpp  -ansi -pedantic -Wall

编译错误是:

dfg.cpp:13: error: qualified name does not name a class before ‘{’ token
dfg.cpp: In instantiation of ‘B<0, float>::C’:
dfg.cpp:25:   instantiated from here
dfg.cpp:20: error: ISO C++ forbids zero-size array

我真正想要归档的是根据枚举值有不同的 Imp 实现(在示例中,我使用 int 而不是枚举,但这不重要)。

有人可以解释为什么不允许这样做吗? 为什么我会收到第一个错误? (这个:限定名没有在‘{’标记之前命名一个类)


关于取决于模板参数的 pimpl 实现,我创建了一个新问题(有更好的例子)here

【问题讨论】:

    标签: c++ templates metaprogramming partial-specialization pimpl-idiom


    【解决方案1】:

    这是无效的:

    template< typename T >
    struct B< 0, T >::C
    {
        typedef T type;
    };
    

    可以专门化类模板的成员,但仅限于这些类模板的隐式实例化。这意味着用简单的英语:仅当您为封闭类模板(您需要专门化其成员)的所有模板参数提供值时。

    template< >
    struct B< 0, int >::C
    {
        typedef T type;
    };
    

    您写的是B&lt;0, T&gt;::C 的定义,它是B&lt;N, T&gt; 的类模板部分特化的成员。这样的部分特化不存在,因此编译器出错了。


    您有多种选择来解决这个问题。一个是

    template< int N, typename T >
    struct B
    {
        template<typename N1, typename T1>
        struct CMember { typedef T1 type[N1]; };
    
        template<typename T1>
        struct CMember<0, T1> { typedef T1 type; };
    
        struct C { 
          typedef typename CMember<N, T>::type type;
        };
    };
    

    请注意,显式特化(非部分)不能直接放入类模板中(因此,template&lt;&gt; struct CMember&lt;0, int&gt; { ... }B 的主体中写入时格式错误)。然后,您需要在B 之外定义“选择器”模板(可能在detail 命名空间中)。

    其他替代方法包括从 CMember 派生并继承其 typedef。

    【讨论】:

      【解决方案2】:

      您不能以这种方式在B 之外定义C - 您正在创建的B 专业化不存在C。如果您想专攻 B::C,则需要专攻 B。您是否尝试执行以下操作?

      template< int N, typename T >
      struct B
      {
          struct C {
              typedef T type[N];
          };
      };
      
      template< typename T >
      struct B< 0, T >
      {
          struct C {
              typedef T type;
          };
      };
      

      或者,您可以执行以下操作:

      template< int N, typename T >
      struct B
      {
          struct C;
      };
      
      template< typename T >
      struct B< 0, T > {
          struct C;
      };
      
      template< typename T >
      struct B< 0, T >::C
      {
          typedef T type;
      };
      
      template< int N, typename T >
      struct B< N, T >::C
      {
          typedef T type[N];
      };
      

      这部分将 B 特化为 0 并向前声明 C,以便可以定义 B&lt;0, T&gt;::C

      【讨论】:

      • 并非如此。我正在使用 pimpl 习惯用法,并尝试根据模板参数对其进行不同的实现。您可以在 struct B 中转发声明 struct C,并在外部定义它,但两者都必须在实例化时定义
      • VJo:你的帖子里没有 pImpl...
      • 结构 C 模拟 pimpl 习惯用法,因为它是在结构 B 中前向声明的。所以,我必须为结构 B 声明模板特化才能使其正常工作?为什么它不能使用它存在的 B 的声明?
      • @VJo:没有什么可以阻止你,例如创建一个完全没有 struct C 的 B 专业化。所以编译器无法知道 B 的特化有一个 C 成员,除非你告诉它,通过向它展示特化。
      • 对,我会创建新问题
      猜你喜欢
      • 2012-07-02
      • 2018-04-09
      • 1970-01-01
      • 2018-08-03
      • 2022-01-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多