Почему специализации шаблонов не могут находиться в разных пространствах имен? - PullRequest
12 голосов
/ 18 июня 2010

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

#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 ]

7 голосов
/ 18 июня 2010

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

4 голосов
/ 18 июня 2010

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

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

0 голосов
/ 18 июня 2010

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

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

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

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

...