12

请看看我想要做什么:

#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::swap、等。而无需通过向?std::numeric_limits中添加一些东西来诉诸未定义的行为。::std::


@AndreyT 以下是我使用它的方式:

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

这可以做到吗?

4

3 回答 3

7

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

因此,您可以专门化一个库模板,并将您的专业化放在 namespacestd中,只要它依赖于用户定义的类型并满足原始模板的要求。

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

只剩下您的专业化满足原始模板要求的要求。对于您的类型,其中大部分可能微不足道。我可以看到的唯一可能不明显的部分是您似乎确实必须为整个模板提供专业化,而不仅仅是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 类型的,并且不需要对整数类型有意义;我相信它们仍然需要实施。

于 2010-06-18T19:04:19.883 回答
5

它使事情复杂化:

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 年的使用之后,很容易说出来:)

于 2010-06-18T18:50:59.257 回答
-4

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

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

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

顺便说一句,“在不同的命名空间中”是什么意思?您希望专业化成为不同名称空间的成员吗?或者您希望您的专业化定义在源代码中的不同名称空间中,但仍保留原始名称空间的成员?

于 2010-06-18T18:43:12.383 回答