11
template<typename T1, typename T2>
class Bimap {
public:
    class Data {
    private:
        template<typename T> Data& set(T);
        template<> Data& set<T1>(typename T1 v) { /*...*/ }
    };
};

That gives me the error:

error: explicit specialization in non-namespace scope 'class Bimap<T1, T2>::Data'

I understand what the error is saying. But why I can't I do this? And how can I fix it?

Albert
  • 65,406
  • 61
  • 242
  • 386
  • 3
    Worth noting that some compilers will support this. – Puppy Sep 19 '10 at 16:20
  • 1
    In C++ you cannot explicitly specialize a member template without explicitly specializing the enclosing class template. What you are trying (namely, specialization) to do is *not possible*. You have to use overloading. Or redesign the whole thing entirely. MSVC++ is a compiler that allows this as an extension though. – AnT stands with Russia Sep 19 '10 at 17:01

2 Answers2

16

One way forget templates, overload:

Data& set(T1 v) { /*...*/ }

but here is a trick which I use sometimes

you can specialize class template within class:

class {
    template<typename T>
    struct function_ {
        static void apply(T);
    };

    template<>
    struct function_<int> {
        ...
    };

    template<typename T>
    void function(T t) { return function_<T>::apply(t); }
Anycorn
  • 50,217
  • 42
  • 167
  • 261
  • +1, yeah, the only sane way to get function template specializations right. – Alexandre C. Sep 19 '10 at 16:54
  • 5
    You *can* explicitly specialize a nested class template within an *ordinary* class. But you *cannot* explicitly specialize a nested class template within another *class template*. The only way to do the latter is to explicitly specialize *both* the enclosing template and the nested template. – AnT stands with Russia Sep 19 '10 at 17:26
  • @Andrey I was not sure about template class inside template class. at any rate, some variation of the trick can probably be made – Anycorn Sep 19 '10 at 17:40
0

@Albert

I had a similar problem when I wanted to add a "trim-excess-capacity" to a custom made container. The std::vector swap trick and changing the declaration of the existing container were not valid options. So I've come up with this:

template <class T, bool isPtr> struct DeleteImp
{
    static void Trim(T* to, unsigned int count);
};

template <class T> struct DeleteImp<T, false>       
{
    static void Trim(T* to, unsigned int count) {}
};

template <class T> struct DeleteImp<T, true>        
{
    static void Trim(T* to, unsigned int count)
    {
        for(unsigned int i=0; i<count; i++)
            delete to[i];
    }
};

used by my container like this:

DeleteImp<T, TypeTraits<T>::isPointer>::Trim(buf + length, truelength-length);

You may also want to check out this resource.