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

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

#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

Это может быть сделано?

12
задан AraK 18 June 2010 в 18:56
поделиться

3 ответа

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-типов и не обязаны быть значимыми для целого типа; я считаю, что их все равно нужно реализовать.

7
ответ дан 2 December 2019 в 23:06
поделиться

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

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

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

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

.
-4
ответ дан 2 December 2019 в 23:06
поделиться

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

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 лет использования :)

4
ответ дан 2 December 2019 в 23:06
поделиться
Другие вопросы по тегам:

Похожие вопросы: