为什么允许嵌套类模板的部分特化,而完全不允许?

时间:2010-03-29 12:15:59

标签: c++ templates metaprogramming

    template<int x> struct A {                                                                                                    
        template<int y> struct B {};.                                                                                             
        template<int y, int unused> struct C {};                                                                                  
    };                                                                                                                            

    template<int x> template<> 
    struct A<x>::B<x> {}; // error: enclosing class templates are not explicitly specialized

    template<int x> template<int unused> 
    struct A<x>::C<x, unused> {}; // ok

那么,如果外部类也不是专用的,为什么不允许内部嵌套类(或函数)的显式特化?奇怪的是,如果我只是部分只需添加一个虚拟模板参数来专门化内部类,我就可以解决这个问题。使事情更丑陋,更复杂,但它确实有效。

我会将完全专业化视为部分特化的子集 - 特别是因为您可以通过添加虚拟参数将每个完整的专业化表达为部分。因此,部分和完全专业化之间的消歧对我来说并没有多大意义。

不幸的是,没有人在comp.std.c ++敢于回答,所以我再次以赏金把它放在这里。

注意:我需要此功能用于一组外部类的内部类的递归模板,而内部参数的特化取决于外部模板参数。

4 个答案:

答案 0 :(得分:26)

我猜测为什么会发生这种情况:完全专业化不再是“模板类/函数”,它们是“真正的”类/方法,并且具有真实(链接器可见)符号。但对于部分专用模板中的完全专用模板,这不是真的。 可能这个决定仅仅是为了简化编译器编写者的生活(并且在编写过程中使编程人员更加努力:P)。

答案 1 :(得分:8)

C ++ Standard在第一种情况下明确禁止成员模板类的完全专业化。根据14.7.3 / 18:

  

在显示的类模板成员或成员模板的显式特化声明中   在命名空间作用域中,成员模板及其一些封闭的类模板可能仍然未经专门化,   除了声明如果它的封闭类不明确地专门化类成员模板   模板也没有明确专门化

答案 2 :(得分:7)

您可以通过将实际工作委托给另一个结构来解决此问题:

namespace detail
{
  template <class T, class U>
  struct InnerImpl {};
}

template <class T>
struct Outer
{
  template <class U>
  struct Inner: detail::InnerImpl<T,U>
  {
  };
};

现在您可以根据需要专注InnerImpl

答案 3 :(得分:4)

支持维吉尔的论点(他比我发布相同的理由更快),考虑一下:

template<typename T1>
class TOuter
  {
  public:
    template<typename T2>
    class TInner
      {
      public:
        T1 m_1;
        T2 m_2;
      };
  };

template<typename T1>
template<>
class TOuter<T1>::TInner<float>
  {
  public:
    T1    m_1;
    float m_2;
 };

由于T1,TInner是完全专业化还是部分专业化?

编辑:

在考虑了其他一些注释之后 - 似乎您希望基于外部类中的模板参数进行完全特化。如果嵌套内部类的实现,那似乎在Visual Studio 2005中起作用:

template<typename T1>
class TOuter
  {
  public:
    template<typename T2>
    class TInner
      {
      public:
        std::string DoSomething() { return "Inner - general"; }
        T2 m_2;
      };

    template<>
    class TInner<T1>
      {
      public:
        std::string DoSomething() { return "Inner - special"; }
        T1 m_1;
      };
  };

TOuter :: TInner将正确地成为TInner的专业化。我无法使用模板外的实现进行编译。