派生类中类模板的部分特化会影响基类

Posted

技术标签:

【中文标题】派生类中类模板的部分特化会影响基类【英文标题】:Partial specialization of a class template in derived class affects base class 【发布时间】:2009-09-11 20:42:01 【问题描述】:

我有一个元函数:

struct METAFUNCION

  template<class T>
  struct apply
  
    typedef T type;
  ;
;

然后我定义一个助手:

template<class T1, class T2>
struct HELPER

;

然后我有第二个元函数,它派生自上面的 METAFUNCTION 并定义了应用结构的部分特化:

struct METAFUNCION2 : METAFUNCION

  template<class T1, class T2>
  struct apply<HELPER<T1, T2> > : METAFUNCION::apply<T2>
  
  ;
;

到目前为止,一切都很好 - 代码在 g++ 4.3.2 下编译。所以我像下面这样使用它:

#include <typeinfo>
#include <string>
#include <cstdlib>
#include <cxxabi.h>

template<typename T>
struct type_info2

  static std::string name()
  
    char *p = abi::__cxa_demangle(typeid(T).name(), 0, 0, 0);
    std::string r(p);
    free(p);
    return(r);
  
;

#include <boost/mpl/apply.hpp>
#include <iostream>

int main()

  std::cout <<
    type_info2<boost::mpl::apply<METAFUNCION, int>::type>::name() <<
    std::endl;
  std::cout <<
    type_info2<boost::mpl::apply<METAFUNCION, HELPER<float, double> >::type>::name() <<
    std::endl;
  std::cout <<
    type_info2<boost::mpl::apply<METAFUNCION2, HELPER<float, double> >::type>::name() <<
    std::endl;
  return(0);

输出:

int
double
double

这让我有点意外:

int
HELPER<float, double>
double

现在,我知道上面的代码不能在 Microsoft Visual C++ 2008 下编译(我不记得该消息,但它是我无法专门在 METAFUNCTION2 结构中应用结构的内容)。

所以我的问题是 - 这个 g++ 行为是否符合标准?我有一种强烈的感觉,这里有问题,但我不是 100% 确定。


出于好奇 - 当我以这种方式重新定义 METAFUNCTION2 时,我的行为符合我的预期:

struct METAFUNCION2 : METAFUNCION

  template<class T>
  struct apply : METAFUNCION::apply<T>
  
  ;
  template<class T1, class T2>
  struct apply<HELPER<T1, T2> > : METAFUNCION::apply<T2>
  
  ;
;

【问题讨论】:

这不是你的真实代码,因为template&lt;class T1, class T2&gt; struct apply&lt;HELPER&lt;T1, T2&gt; &gt; : METAFUNCION::apply&lt;T2&gt; ; 不会编译。我不再在那里阅读你的问题了。 很遗憾您没有指定您使用的编译器和版本。我已经非常清楚地表明该代码可以在 g++ 4.3.2 上编译并且不能在 VC++ 2008 上编译。 @Tomek:我使用的是 Brain 1.0。 :) 代码完全错误。很抱歉过早地忽略了您的问题,但是这里的问题中粘贴了太多错误的代码,以至于当错误成为问题的核心时,我养成了停止打扰的习惯。我不敢相信,gcc4 会出错... 据我了解这个问题,不过,他并没有声称代码是正确的。他问哪个编译器是正确的。我也提出过这样的问题。我用 gcc4.4 进行了测试,是的,它弄错了(至少,与 Comeau 不同,它本身说了很多哈哈)。 @lib:他写了“代码在g++ 4.3.2下编译”。我不相信。我错了。这就是我说对不起的原因。 【参考方案1】:

所以我提交了a bug on gcc

【讨论】:

我相信你的标准引用并不适用,因为你没有声明一个明确的特化(你是在声明和定义一个部分特化),并且因为类模板的声明是特化的i>已经在范围内。不过,我还没有找到一个明确的要求,即成员模板的部分特化应该是同一类的成员。 好吧,VC++ 拒绝代码,所以至少有一些事情需要考虑。正如我所写 - 我不希望部分专业化来处理继承树。至少当我“发明”那段代码时,我是这样想的。 @Tomek,这里有同样的怀疑 :) 我也不认为部分专业化应该在树上起作用。主要和部分特化模板都是同一模板的“替代定义”(原始措辞),因此它们应该在同一类范围内为模板提供定义,而不是在派生类范围内(这意味着定义发生在模板声明之外的另一个范围)。但我希望在标准中明确引用这一点。 对于追随者,我刚刚收到一封来自 gcc bugzilla 的电子邮件,说此错误已在 gcc 4.5.0 中修复。【参考方案2】:

以下代码是非法的:

struct METAFUNCION2 : METAFUNCION

  template<class T1, class T2>
  struct apply<HELPER<T1, T2> > : METAFUNCION::apply<T2>
  
  ;
;

根据 C++ 标准 14.7.3/3:

显式特化的函数模板或类模板的声明应在范围内 显式特化的声明点。

编辑:根据Core Issue 727,此限制不适用于成员模板的部分特化。

【讨论】:

目前还不清楚是否可以在其派生类中专门化基类的内部模板,以及它是否应该仅在派生类或基类中可见。

以上是关于派生类中类模板的部分特化会影响基类的主要内容,如果未能解决你的问题,请参考以下文章

在派生类中使用模板基类模板构造函数

继承中类的作用域

派生类中隐藏的基类模板成员函数,尽管参数列表不同

c++继承是如何工作的?

在模板派生类中,为啥我需要在成员函数中使用“this->”来限定基类成员名称?

虚拟方法的 C++ 部分模板特化