代码之家  ›  专栏  ›  技术社区  ›  Khaled Alshaya

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

  •  12
  • Khaled Alshaya  · 技术社区  · 14 年前

    请看我想做什么:

    #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::max , std::swap , std::numeric_limits 等。不诉诸未定义的行为 ::std:: ?


    @Andreyt这是我想如何使用它:

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

    能做到吗?

    3 回复  |  直到 14 年前
        1
  •  7
  •   Jerry Coffin    14 年前

    C++ 2003,y7.174.3.1/1:“一个程序可以将任何标准库模板的模板特化添加到命名空间STD。标准库模板的专门化(完整或部分)导致未定义的行为,除非声明依赖于外部链接的用户定义的名称,除非专业化符合标准。原始模板的库要求。“

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

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

    这只剩下您的专业化满足原始模板要求的需求。对于您的类型,其中大部分都可能是无关紧要的。我能看到的唯一不明显的一点是,您似乎必须为整个模板提供专门化,而不仅仅是 numeric_limits::max() . 例如,您必须执行如下操作(例如,对于128位无符号整数类型,应该在Ballpark中):

    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类型的,对于整数类型来说不需要有意义;我相信它们仍然需要实现。

        2
  •  3
  •   Matthieu M.    14 年前

    它使事情复杂化:

    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年来说明:

        3
  •  -4
  •   AnT stands with Russia    14 年前

    为什么会出现这样的问题?如果不理解,甚至很难回答。

    专门化修改主模板。它不能以任何方式与主模板“分离”。在某种程度上,作为一个高层次的概念,它仍然是相同的模板(即使在较低层次上,它被定义为一个独立的模板)。因此,出于明显的原因,它与主模板位于同一名称空间中。

    对不起,我只是不能提供更好的解释,因为我不明白这样的问题是如何产生的。

    顺便问一下,“在不同的名称空间”是什么意思?您想让专门化成为不同名称空间的成员吗?或者您希望在源代码的另一个名称空间中定义专门化,但仍然是原始名称空间的成员?