Смешивание частичной специализации шаблона и параметров шаблона по умолчанию - PullRequest
6 голосов
/ 27 декабря 2011

Я хотел бы создать общий векторный класс и создать специализацию для нескольких случаев. Примерно так (не компилируется, но, надеюсь, сообщает о моих намерениях):

template<int dim, typename T = float>
class Vector
{
public:
    typedef Vector<dim, T> VecType;

    Vector() { /**/ }
    Vector(const VecType& other) { /**/ )
    Vector& operator=(const VecType& other) { /**/ }

    VecType operator+(const VecType& other) { /**/ }    
    VecType operator-(const VecType& other) { /**/ }    
    T operator*(const VecType& other) { /**/ }

private:
    std::array<T, dim> elements;
};

template<int dim, typename T>
class Vector<2>
{
public:
    T x() const { return elements[0]; }
    T y() const { return elements[1]; }
};

template<int dim, typename T>
class Vector<3>
{
public:
    T x() const { return elements[0]; }
    T y() const { return elements[1]; }
    T z() const { return elements[2]; }
};

Другими словами, я хочу, чтобы тип элементов по умолчанию был float, и я хочу иметь методы доступа x() и y() для случая dim = 2 и x(), y() и z() для случая dim = 3. Меня немного смущают сообщения об ошибках:

vector.h: 56: 10: ошибка: объявление int dim

vector.h: 6: 10: ошибка: шаблон теней parm "int dim"

(то же самое для T).

Как я могу сделать это правильно? (если это возможно)

Ответы [ 3 ]

10 голосов
/ 27 декабря 2011

1.

При частичной специализации шаблона следует указывать только те параметры шаблона, которые фактически являются параметрами.Поскольку вы уже установили dim как 2 или 3, нет необходимости указывать его снова.

template<typename T>
class Vector<2, T>
{
   ....

2.

Специализация класса действительно означает изменение всей декларации.Следовательно, члены универсального Vector<dim, T> не будут доступны в специализированном Vector<2, T>.Вы можете сделать обобщенный Vector<dim, T> как внутренний базовый класс и создать подкласс только для специализации:

template<int dim, typename T>
class VectorImpl;

...

template<int dim, typename T = float>
class Vector : public VectorImpl<dim, T> {};

template<typename T>
class Vector<2, T> : public VectorImpl<2, T>
{
public:
   T x() const { ... }
};

3.

Вам не нужно определять VecType!Внутри шаблона вы можете просто использовать Vector.Он будет автоматически выведен для ссылки на класс с правильными параметрами.

Конечный результат, который компилируется:

#include <array>

template<int dim, typename T>
class VectorImpl
{
public:
    //typedef Vector<dim, T> VecType;

    VectorImpl() {  }
    VectorImpl(const VectorImpl& other) {  }
    VectorImpl& operator=(const VectorImpl& other) { return *this; }

    VectorImpl operator+(const VectorImpl& other) { return *this; }
    VectorImpl operator-(const VectorImpl& other) { return *this; }
    T operator*(const VectorImpl& other) { return 0; }

protected:
    std::array<T, dim> elements;
};

template <int dim, typename T = float>
class Vector : public VectorImpl<dim, T> {};

template<typename T>
class Vector<2, T> : public VectorImpl<2, T>
{
public:
    T x() const { return this->elements[0]; }
    T y() const { return this->elements[1]; }
};

template<typename T>
class Vector<3, T> : public VectorImpl<2, T>
{
public:
    T x() const { return this->elements[0]; }
    T y() const { return this->elements[1]; }
    T z() const { return this->elements[2]; }
};

int main()
{
    Vector<2> v;
    Vector<3> vv;
    v + v;
    vv.z();
}
2 голосов
/ 27 декабря 2011

Частичная специализация должна выглядеть примерно так:

template <int Dim, typename T = float> class Vector; // primary

template <typename T> class Vector<2, T> { /* ... */ };
template <typename T> class Vector<3, T> { /* ... */ };
0 голосов
/ 27 декабря 2011

Вы можете сделать это так:

#include <array>
template<int dim, typename T = float>
class Vector
{
public:
    typedef Vector<dim, T> VecType;
    Vector() { /**/ }
    Vector(const VecType& other) { /**/ }
private:
    std::array<T, dim> elements;
};

template<typename T>
class Vector<2, T>
{
public:
    T x() const { return elements[0]; }
    T y() const { return elements[1]; }
private:
    std::array<T, 2> elements;
};

template<typename T>
class Vector<3, T>
{
public:
    T x() const { return elements[0]; }
    T y() const { return elements[1]; }
    T z() const { return elements[2]; }
private:
    std::array<T, 3> elements;
};

int main(int argc, char **argv)
{
    Vector<2> v2;
    v2.x();
    Vector<3> v3;
    v3.z();
    return 0;
}

Это можно скомпилировать в gcc 4.5.2 (не запускать его ...).

Однако, таким образом,Вы не сможете использовать переменную-член функции-члена, определенную в основном шаблоне в специализации.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...