1

I'm trying to use type traits like in "Modern C++ Design" using a template to determine if a type has a variable size or not. e.g. a string requires variable size storage, an int has fixed-size storage. This code works on Microsoft C++, now I'm porting to mac and I get the error:

explicit specialization is not allowed in the current scope

What's the correct way to specialize this?

template <typename T>
class MyTypeTraits
{
    template<class U> struct VariableLengthStorageTraits
    {
        enum { result = false };
    };
    template<> struct VariableLengthStorageTraits<std::wstring>
    {
        enum { result = true };
    };

public:
    enum{ IsVariableLengthType = VariableLengthStorageTraits<T>::result };
};
TooTone
  • 7,129
  • 5
  • 34
  • 60
Jeff
  • 402
  • 1
  • 6
  • 14
  • A string also has "fixed-size storage", depending on what you mean by "storage". – Kerrek SB Oct 09 '11 at 22:16
  • In this case I'm serializing the objects to disk. With ints, I simply store the 4 bytes. With strings or arrays I first store the number-of-elements, then the actual elements. So this code helps me store the raw bytes of the objects in the most compact format. – Jeff Oct 09 '11 at 22:52
  • also a problem on recent icc with std=c++14 – TooTone Jun 04 '19 at 09:16

3 Answers3

5

The 2003 C++ standard only allows member template specialization outside of the enclosing class definition. Also, the out-of-definition specialization must be an explicit full specialization of the enclosing template. Microsoft C++ is non-standard in this regard. The fix is simple, just move the inner template out of the enclosing template, since the inner template doesn't need its enclosing class template arguments:

template<class U> struct VariableLengthStorageTraits
{
    enum { result = false };
};

template<>
struct VariableLengthStorageTraits<std::wstring>
{
    enum { result = true };
};

template <typename T>
struct MyTypeTraits
{
    enum{ IsVariableLengthType = VariableLengthStorageTraits<T>::result };
};
Maxim Egorushkin
  • 131,725
  • 17
  • 180
  • 271
4

You cannot add specializations of nested classes inside the outer class definition. It'd be simpler, and more reusable, to make the inner trait class a separate entity, though:

#include <type_traits>

template <typename> struct has_variable_length;  // intentionally undefined!
template <> struct has_variable_length<std::wstring> : std::true_type  { };
template <> struct has_variable_length<int>          : std::false_type { };
// ...

template <typename T> struct MyTraits
{
  static const bool variable_length = has_variable_length<T>::value;
  // ...
};

You could wrap the individual trait classes into a detail namespace if you prefer.

Kerrek SB
  • 464,522
  • 92
  • 875
  • 1,084
0

Move the function specialization outside of class and inside a .cpp file, it doesn't work with headers.

RelativeGames
  • 1,593
  • 2
  • 18
  • 27