3

I have a situation similar to this:

template<class A, class B>
class MyClass<A, B>
{
  ...
  static A RARELY_USED_A;
}

// Seems to work but does not cover all possible cases, since 
// there may be instances of A that have no numeric limits.
template<class A, class B>
A MyClass<A, B>::RARELY_USED_A= std::numeric_limits<A>::max();

From what I saw this seems to work. However, strings may be used as A under some circumstances and so I thought I'd simply create a specialization for this special case.

// Does not complile
template<class B>
string MyClass<string, B>::RARELY_USED_A= "";

unfortunately this does not complie properly with error msg:

error: template definition of non-template 'std::string MyClass<std::basic_string<char, std::char_traits<char>, std::allocator<char> >, B>::RARELY_USED_A'

Note that, on the othre hand, a full specialization seems to work (untested at runtime but compiles)

// This complies but is not gernic enough and hence useless to me
template<>
string MyClass<string, string>::RARELY_USED_A= "";

I assume, I must be doing something wrong. I would be really grateful if you could point out what exactly it is. I thought partical specializations were supposed to work this way.

Thanks a lot in advance.

e: edited the name of the DEFAULT_A to RARELY_USED_A, because I thought that "default" was misleading somehow

b.buchhold
  • 3,837
  • 2
  • 24
  • 33

3 Answers3

4

Use inheritance to reuse and specialize without duplicating all the common code:

template<typename A>
struct RarelyUsedShared
{
    static A RARELY_USED_A;
};

template<typename A>
A RarelyUsedShared<A>::RARELY_USED_A = std::numeric_limits<A>::max();

template<>
string RarelyUsedShared<string>::RARELY_USED_A = "";

template<typename A, typename B>
class MyClass<A, B> : RarelyUsedShared<A>
{
  ...
};

Note that this will result in sharing the member across various B, which is ok if the member should be const. If not, the helper can take two template parameters, and you can partially specialize it:

template<typename A, typename B>
struct RarelyUsedNotShared
{
    static A RARELY_USED_A;
};

template<typename A, typename B>
A RarelyUsedNotShared<A, B>::RARELY_USED_A = std::numeric_limits<A>::max();

template<typename B>
struct RarelyUsedNotShared<string, B>
{
    static A RARELY_USED_A;
};

typename<typename B>
string RarelyUsedNotShared<string, B>::RARELY_USED_A = "";

template<typename A, typename B>
class MyClass<A, B> : RarelyUsedNotShared<A, B>
{
  ...
};
Ben Voigt
  • 277,958
  • 43
  • 419
  • 720
  • Thank you. Sounds good. I still wonder why there is this limitation of partial specialization. But I guess this answer solves my problem in an elegant way. – b.buchhold Jul 14 '11 at 17:10
  • Now I have another problem. Since MyClass is a container type with many possible instatiations, I cannot split it in .h and .cpp files and have to have the whole thing in the header file. Unfortunately doing this get's my multiple definitions of RARELY_USED_A when linking a binary from multiple objects that use MyClass. – b.buchhold Jul 14 '11 at 17:55
  • @b.buchhold: That's a new question entirely, you'd have that problem even without specialization, and needs to be asked separately. Moreover, I think it's already been answered, so first do a search for "template static multiple definition". – Ben Voigt Jul 14 '11 at 18:13
1

You need to give a partial specialization to your entire class, not just a single member.

n. m. could be an AI
  • 112,515
  • 14
  • 128
  • 243
  • hmm, that would be really annoying because it would be nothing but duplicate code for everything instead that one single member. Also I wonder why a full specialization is possible for only this one member. – b.buchhold Jul 14 '11 at 16:59
  • @b.buchhold: Use a helper class, that has just this one member. Then you can specialize it without code duplication. Your main class can inherit from it. – Ben Voigt Jul 14 '11 at 17:02
  • ... and yes, it's a bit of a pain. Note that in your working case, n.m., you're not really specialising the function at all but providing a definition for one member of _one_ specialised template instance of `MyClass`. I think. – Lightness Races in Orbit Jul 14 '11 at 17:04
  • and yes, it's a horrific, insane, ridiculous pain. – Puppy Jul 14 '11 at 17:05
0

If your RARELY_USED is const, you could use a little helper class:

template <class A, class B>
const A MyClass<A, B>::RARELY_USED_A = Helper<A>::value;

/*...*/

#include <limits>
#include <string>

template <typename A> struct Helper { static const A RARELY_USED_A; };
template <typename A> const A Helper<A>::RARELY_USED_A = std::numeric_limits<A>::max();

template <> struct Helper<std::string> { static const std::string RARELY_USED_A; };
const std::string Helper<std::string>::RARELY_USED_A = "";
Kerrek SB
  • 464,522
  • 92
  • 875
  • 1,084
  • I don't think this compiles, because neither functions calls nor initialization of strings is possible for static/const stuff, if i recall correctly. – b.buchhold Jul 14 '11 at 18:04
  • Even in C++0x where `max()` is `constexpr`? Haven't tested it, though, so it's possible that this doesn't work. – Kerrek SB Jul 14 '11 at 18:15
  • `static` members have to be defined outside the class, even if they're initialized inside the class. – Ben Voigt Jul 14 '11 at 18:16