4

Code speaks:

template<typename Group>
struct Vector3D {
    Group x, y, z;
    Vector3D(Group x, Group y, Group z) : x(x), y(y), z(z) {
    }
    template<int p> Group Norm() const;
};

template<typename Group> template<int p> 
Group Vector3D<Group>::Norm() const {
    return pow( pow(x, p) + pow(y, p) + pow(z, p), (1.0 / p) );
}

/*
template<typename Group> template<>
Group Vector3D<Group>::Norm<2>() const {
    return sqrt( x * x + y * y + z * z );
}*/

The commented block fails to compile in vc11(vs2012)

Could anyone help to point out what is the right way to partial specialize the Norm function?

buaagg
  • 599
  • 6
  • 11

2 Answers2

4

You cannot specialize a member template without specializing the class itself. For that you will need to use a different mechanism. You could for example, use an int2type template to map the template argument into a type that can be passed as argument to a set of overloaded templates. Consider this oversimplified sketch of how it could be done:

template <int N> struct int2type {};

template <int N> void normImpl(int2type<N>*) {
...
}
void normImpl(int2type<2>*) {
...
}
template <int N> void norm() {
   return normImpl(static_cast<int2type<N>*>(0));
}

This can be implemented inside your class (except that the int2type is a good utility to have outside).

David Rodríguez - dribeas
  • 204,818
  • 23
  • 294
  • 489
1

As is the case in some of these types of scenarios, another level of indirection helps...

#include <iostream>
#include <cmath>
using namespace std;

template <typename Group, int p>
struct ApplyNorm
{
    static Group apply(Group x, Group y, Group z)
    { return pow( pow(x, p) + pow(y, p) + pow(z, p), (1.0 / p) ); }
};

// Here specialize for 2
template <typename Group>
struct ApplyNorm<Group, 2>
{
    static Group apply(Group x, Group y, Group z)
    { 
        std::cout << "spec: " << std::endl;
        return sqrt( x * x + y * y + z * z ); 
    }
};


template<typename Group>
struct Vector3D {
    Group x, y, z;
    Vector3D(Group x, Group y, Group z) : x(x), y(y), z(z) {
    }
    template<int p> Group Norm() const;
};

template<typename Group> template<int p> 
Group Vector3D<Group>::Norm() const {
    return ApplyNorm<Group, p>::apply(x, y, z); // use the helper...
}

int main() {
    // your code goes here
    Vector3D<double> v(1., 2., 3.);
    std::cout << v.Norm<1>() << std::endl;
    std::cout << v.Norm<2>() << std::endl;
    return 0;
}
Nim
  • 33,299
  • 2
  • 62
  • 101
  • +1 Did not mention in my answer, but among the different alternatives, forwarding to a static member of a class template that can be partially specialized is another good option – David Rodríguez - dribeas Nov 22 '13 at 15:35