views:

99

answers:

3

Hi,

Please, see what I am trying to do:

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

This isn't allowed. Could you please, clarify why can't specializations be in different namespaces, and what are the available solutions? Also, is it something fixed in C++0x?

This would allow me for example, to specialize std::max, std::swap, std::numeric_limits, etc.. without resorting to undefined behavior by adding something to ::std::?


@AndreyT Here is how I though I would use it:

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

Can this be done?

+1  A: 

Why would such a question even arise? Without understanding that it is difficult to even begin answering it.

Specialization modifies the main template. It is not "detachable" in any way from the main template. In certain way, as a high-level concept, it is still the same template (even though at lower level it is defined as an independent one). So, for obvious reasons, it is in the same namespace as the main template.

Sorry, I just can't provide a better explanation, since I don't understand how such a question can arise.

BTW, what do you mean by "in different namespace"? You want the specialization to be a member of different namespace? Or you want your specialization to be defined in a different namespace in the source code, but still remain a member of the original namespace?

AndreyT
+1  A: 

It complicates things:

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
}

I understand your frustration, I often wished for the same thing. It seems definitely possible and I certainly don't buy the logical grouping argument, however I must admit that it would require even more effort from the compiler writers, and parsing C++ correctly is already difficult enough as it stands.

Templates are a bit messy in C++ if you want my opinion, but then it's easy to say with the benefit of experience and after having seen 20 years of use :)

Matthieu M.
@Matthiew M. Thanks. Good answer.
AraK
+3  A: 

C++ 2003, §17.4.3.1/1: "A program may add template specializations for any standard library template to namespace std. Such a specialization (complete or partial) of a standard library template results in undefined behavior unless the declaration depends on a user-defined name of external linkage and unless the specialization meets the standard library requirements for the original template."

As such, you're allowed to specialize a library template, and put your specialization in namespace std, as long as it depends on a user defined type and meets the requirements of the original template.

The code you have in your edited question seems to be a specialization for a user-defined name that (presumably) has external linkage, so you shouldn't have any problem with that part of things.

That leaves only the requirement that your specialization meet the requirements of the original template. For your type, most of this will probably border on trivial. The only part I can see that might not be obvious is that you do seem to have to provide a specialization for the whole template, not just numeric_limits::max(). I.e., you'll have to do something like (example should be in the ballpark for a 128-bit unsigned integer type):

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

Quite a few of those are really for FP types, and aren't required to be meaningful for an integer type; I believe they still need to be implemented.

Jerry Coffin
Thanks for providing the answer. A tiny clarification please, what is meant by external linkage. If my library is a header only, the behavior is undefined?
AraK
No -- "external linkage" mostly means it isn't 'static' or in an anonymous namespace.
Jerry Coffin
Great. It is crystal clear now :)
AraK
Stuff in an unnamed namespace still has external linkage.
Johannes Schaub - litb
@Johannes: Thanks for the correction.
Jerry Coffin