【问题标题】:Explicit specialization in non-namespace scope [duplicate]非命名空间范围的显式专业化[重复]
【发布时间】:2011-03-04 09:56:01
【问题描述】:
template<typename T>
class CConstraint
{
public:
    CConstraint()
    {
    }

    virtual ~CConstraint()
    {
    }
    
    template <typename TL>
    void Verify(int position, int constraints[])
    {       
    }

    template <>
    void Verify<int>(int, int[])
    {   
    }
};

在 g++ 下编译会出现以下错误:

非命名空间范围'class CConstraint'中的显式特化

在 VC 中,它编译得很好。谁能告诉我解决方法?

【问题讨论】:

标签: c++ templates gcc


【解决方案1】:

VC++ 在这种情况下是不兼容的——显式特化必须在命名空间范围内。 C++03,§14.7.3/2

应在模板所属的命名空间中声明显式特化,或者,对于成员模板,应在封闭类或封闭类模板所属的命名空间中声明。
类模板的成员函数、成员类或静态数据成员的显式特化应在类模板所属的命名空间中声明。

此外,由于 C++03,§14.7.3/3,您还存在一个问题,即如果不明确专门化包含类,您就无法专门化成员函数,因此一种解决方案是让Verify() 转发到一个可能是专门的免费函数:

namespace detail {
    template <typename TL> void Verify     (int, int[]) {}
    template <>            void Verify<int>(int, int[]) {}
}

template<typename T> class CConstraint {
    // ...
    template <typename TL> void Verify(int position, int constraints[]) {
        detail::Verify<TL>(position, constraints);
    }
};

【讨论】:

  • 在这种情况下不合规:一如既往:) ?模板和 VC++ 不能很好地混合在一起:/
  • 在某种意义上它是不合规的,它会让你做一些标准通常不允许的事情——这对于一开始就合规的代码来说不是问题(你编写这样的代码,对吧?~)。真正的一致性问题是它不能编译标准要求编译的东西,或者行为与指定的不同。
  • 就像由于缺少两阶段查找而引起的微妙陷阱......:|
  • 语言开发人员为什么要对程序员开发人员这样做?他们在想吗,How can we make this language any more difficult to read and write?
  • 这个答案不再正确,现在允许在符合 C++14(及更高版本)编译器的类范围内进行特化:wg21.cmeerw.net/cwg/issue727
【解决方案2】:

解决它的另一种方法是委托给私有函数并重载该函数。这样您仍然可以访问*this 的成员数据和外部模板参数类型。

template<typename T>
struct identity { typedef T type; };

template<typename T>
class CConstraint
{
public:

  template <typename TL>
  void Verify(int position, int constraints[])
  {
    Verify(position, constraints, identity<TL>());
  }

private:
  template<typename TL>
  void Verify(int, int[], identity<TL>)
  {

  }

  void Verify(int, int[], identity<int>)
  {

  }
};

【讨论】:

  • 非常感谢。我也在寻找这个,因为我需要访问它。希望我能选择 2 个答案。
  • 如果我是你,我会选择这个答案。 @Johannes:你的回答很完美,谢谢。
  • 谢谢,谢谢,谢谢 Johannes Schaub 的回答。
  • 这个答案比接受的答案有用得多。
  • 自 C++11 出现以来有什么变化吗?
【解决方案3】:

只需将模板特化放在类声明之外。 gcc 不允许内联模板特化。

作为另一种选择,只需删除行 模板 似乎对我有用。

【讨论】:

  • 第一句话很重要:“gcc 不允许内联模板专业化”。
  • 删除 template&lt;&gt; 也对我有用。
【解决方案4】:

更好的是:您可以将部分特化与默认模板参数结合起来。这种方式对 VC++ 代码的修改很小,因为不需要修改对专用函数的调用。

template <typename TL, class Dummy=int>
void Verify(int position, int constraints[])
{
}

template <class Dummy=int>
void Verify<int, Dummy>(int, int[])
{
}

【讨论】:

  • 默认模板参数在 C++03 中是不允许的,只有在 C++0x/11 中才允许。
  • 对不起,我错了:你不能部分特化一个函数。
  • @Xeo:我猜你的意思是不允许在 C++03 中使用函数? “默认模板参数是在模板参数中= 之后指定的模板参数 (14.3)。可以为任何类型的模板参数(类型、非类型、模板)指定默认模板参数。可以在类模板声明或类模板定义中指定默认模板参数。不应在函数模板声明或函数模板定义中指定默认模板参数,也不应在模板参数列表中指定类模板成员的定义。"
【解决方案5】:

您可能无法明确地专门化成员模板,但您可以部分地专门化它。如果您添加第二个参数“int dummyParam”并将其添加到特化中,它应该适用于两个编译器。

并不是我在 10 多秒前就知道这一点,而是在谷歌上搜索同样的错误,我遇到了 this link,它对我的​​成员模板专业化有效。

【讨论】:

  • 你不能部分特化一个函数
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-08-12
  • 1970-01-01
  • 2018-09-17
  • 2014-01-29
相关资源
最近更新 更多