为什么不允许模板特化在不同的命名空间中?

时间:2010-06-18 18:38:05

标签: c++ templates namespaces template-specialization

请看看我想做什么:

#include <iostream>
namespace first
{
 template <class T>
 class myclass
 { 
  T t;
 public:
  void who_are_you() const
  { std::cout << "first::myclass"; }
 };
}
namespace second
{
 using first::myclass;
 template <>
 class myclass <int>
 {
  int i, j;
 public:
  void who_are_you() const
  { std::cout << "second::myclass"; }
 };
}

这是不允许的。请问,澄清为什么不能在不同的命名空间中进行专业化,以及有哪些可用的解决方案?还有,它是用C ++ 0x修复的吗?

这样我就可以专门化std::maxstd::swapstd::numeric_limits等,而无需通过向::std::添加内容来诉诸未定义的行为?


@AndreyT以下是我将如何使用它:

// my_integer is a class
std::numeric_limits<my_integer>::max(); // specialized std::numeric_limits for my_integer

可以这样做吗?

3 个答案:

答案 0 :(得分:7)

C ++ 2003,§17.4.3.1/ 1:“程序可以将任何标准库模板的模板特化添加到命名空间std。标准库模板的这种特化(完整或部分)会导致未定义的行为,除非声明取决于在用户定义的外部链接名称上,除非专业化符合原始模板的标准库要求。“

因此,您可以专门化库模板,将您的专业化放在命名空间std中,只要它取决于用户定义的类型并满足要求原始模板。

您编辑的问题中的代码似乎是用户定义名称的特殊化(可能)具有外部链接,因此您不应该对这部分内容有任何问题。

只留下您的专业化要求符合原始模板要求的要求。对于你的类型,大多数这可能是微不足道的。我可以看到的唯一可能不明显的部分是你似乎必须为整个模板提供专业化,而不仅仅是numeric_limits::max()。即,你必须做类似的事情(例如,应该在128位无符号整数类型的球场):

namespace std { 
template <>
class numeric_limits<my_integer> {
public:

    static const bool is_specialized = true;
    static T min() throw() { return 0;
    static T max() throw() { return /* 2^128-1 */; } // ***
    static const int digits = 128;
    static const int digits10 = 38;
    static const bool is_signed = false;
    static const bool is_integer = true;
    static const bool is_exact = true;
    static const int radix = 2;
    static T epsilon() throw() { return 0; }
    static T round_error() throw() { return 0; }
    static const int min_exponent = 0;
    static const int min_exponent10 = 0;
    static const int max_exponent = 0;
    static const int max_exponent10 = 0;
    static const bool has_infinity = false;
    static const bool has_quiet_NaN = false;
    static const bool has_signaling_NaN = false;
    static const float_denorm_style has_denorm = denorm_absent;
    static const bool has_denorm_loss = false;
    static T infinity() throw() { return 0; }
    static T quiet_NaN() throw() { return 0; }
    static T signaling_NaN() throw() { return 0; }
    static T denorm_min() throw() { return 0; }
    static const bool is_iec559 = false;
    static const bool is_bounded = true;
    static const bool is_modulo = true;
    static const bool traps = false;
    static const bool tinyness_before = false;
    static const float_round_style round_style = round_toward_zero;
};
}

其中很多都是针对FP类型的,并且对于整数类型不需要有意义;我相信它们仍然需要实施。

答案 1 :(得分:4)

使事情变得复杂:

namespace first
{
  template <class T> class TArray;
}

namespace second
{
  using first::TArray;

  template <class U> class TArray < Node<U> >;
  //                              ^
  // Only there do you realize it's a specialization and not another template
}

我理解你的沮丧,我经常希望同样的事情。它似乎绝对可能,我当然不会购买逻辑分组参数,但我必须承认它需要编译器编写者更多的努力,正确解析C ++已经足够困难了。

如果您想要我的意见,C ++中的模板有点混乱,但随后经验和使用20年之后很容易说:)

答案 2 :(得分:-4)

为什么会出现这样的问题?没有理解甚至很难开始回答它。

专业化修改主模板。它与主模板无任何“可拆卸”。在某种程度上,作为一个高级概念,它仍然是相同的模板(即使在较低级别它被定义为一个独立的模板)。因此,出于显而易见的原因,它与主模板位于相同的命名空间中。

对不起,我无法提供更好的解释,因为我不明白这样的问题是怎么出现的。

顺便说一下,“你在不同的命名空间中”是什么意思?您希望专门化是不同命名空间的成员吗?或者您希望在源代码中的不同命名空间中定义您的特化,但仍然是原始命名空间的成员?