Подтвердить что ты не робот

Почему специализация шаблонов не допускается в разных пространствах имен?

Пожалуйста, посмотрите, что я пытаюсь сделать:

#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"; }
 };
}

Это запрещено. Не могли бы вы прояснить , почему не может быть специализациям в разных пространствах имен и каковы доступные решения? Кроме того, это что-то фиксированное в С++ 0x?

Это позволило бы мне, например, специализировать std::max, std::swap, std::numeric_limits и т.д., не прибегая к поведению undefined, добавив что-то в ::std::?


@AndreyT Вот как я, хотя я бы использовал его:

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

Можно ли это сделать?

4b9b3361

Ответ 1

С++ 2003, §17.4.3.1/1: "Программа может добавлять специализированные шаблоны для любого шаблона стандартной библиотеки в пространство имен std. Такая специализация (полная или частичная) стандартного шаблона библиотеки приводит к поведению undefined, если только объявление зависит от пользовательского имени внешней привязки и если специализация не соответствует требованиям стандартной библиотеки для исходного шаблона."

Таким образом, вы можете специализировать шаблон библиотеки и ставить свою специализацию в пространстве имен std, если это зависит от определенного пользователем типа и соответствует требованиям исходного шаблона.

Код, который у вас есть в вашем отредактированном вопросе, по-видимому, является специализацией для определяемого пользователем имени, которое (предположительно) имеет внешнюю связь, поэтому у вас не должно быть проблем с этой частью вещей.

Это оставляет только требование, чтобы ваша специализация отвечала требованиям исходного шаблона. Для вашего типа, большая часть этого, вероятно, граничит с тривиальным. Единственная часть, которую я вижу, может быть не очевидна, так это то, что вам, похоже, нужно предоставить специализацию для всего шаблона, а не только numeric_limits::max(). I.e., вам нужно будет сделать что-то вроде (пример должен быть в шале для 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 и не требуют значимого для целочисленного типа; Я считаю, что они все равно должны быть реализованы.

Ответ 2

Это усложняет вещи:

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 a specialization and not another template
}

Я понимаю ваше разочарование, я часто желал того же. Кажется, это определенно возможно, и я, конечно же, не покупаю аргумент логической группировки, однако я должен признать, что это потребует еще больших усилий от авторов компилятора, и правильная синтаксическая обработка С++ уже достаточно сложна, поскольку она стоит.

Шаблоны немного запутаны на С++, если вы хотите мое мнение, но тогда легко сказать с пользой опыта и после 20 лет использования:)

Ответ 3

Почему такой вопрос возникнет? Не понимая, что трудно даже начать отвечать на него.

Специализация изменяет основной шаблон. Он не "отделяется" каким-либо образом от основного шаблона. В определенном смысле, как концепция высокого уровня, это все тот же шаблон (хотя на более низком уровне он определяется как независимый). Таким образом, по очевидным причинам он находится в том же пространстве имен, что и основной шаблон.

Извините, я просто не могу дать лучшего объяснения, так как я не понимаю, как может возникнуть такой вопрос.

Кстати, что вы подразумеваете под "в разных пространствах имен"? Вы хотите, чтобы специализация была членом другого пространства имен? Или вы хотите, чтобы ваша специализация была определена в другом пространстве имен в исходном коде, но все еще остается членом исходного пространства имен?