Может ли T в шаблоне <typename T> использовать наследование? - PullRequest
4 голосов
/ 27 августа 2011

Я хочу сделать что-то вроде этого:

template <typename T:public Vertex> addTri( T v1, T v2, T v3 )
{
    // Take v1.pos, v2.pos, v3.pos and create a geometric repn..
    Triangle tri( v1.pos, v2.pos, v3.pos ) ; // all vertices will 
    // have to have a .pos member.

    // Create the vertex buffer..
    VertexBuffer<T> vb ...
}

Так как это не работает, это мой обходной путь ..

template <typename T> addTri( T v1, T v2, T v3 )
{        
    Vertex* p1 = (Vertex*)&v1 ;
    // This is a very "shut up C++, I know what I'm doing" type cast.
    // I'd like for C++ to know that all vertex types (T in this case)
    // __will__ have a Vector member .pos.

    Triangle tri( p1->pos, p2->pos, p3->pos ) ; 
    // Create the vertex buffer..
    VertexBuffer<T> vb ...
}

Фон

В случае, если вам интересно, я пытаюсь написать общий код для обработки создания треугольника. Каждая вершина должна иметь .pos член, потому что каждая вершина должна иметь позицию в пространстве.

Однако не каждый тип вершины будет иметь текстурную координату. Не каждая вершина будет иметь цвет. Отсюда и параметризованные типы.

Аналогичный подход используется в XNA VertexBuffer.SetData<T>.

Ответы [ 5 ]

10 голосов
/ 27 августа 2011

Нельзя указать ограничение типа в аргументе типа шаблона.Однако, как правило, вам не нужно.

Если вы просто сделаете:

template <typename T> addTri( T v1, T v2, T v3 )
{
    Vertex &v1r = v1;
    // ....
}

Это будет работать, если функция создается с производной от Vertex.Это создаст (неясную) ошибку, если T & является не конвертируемым в Vertex &.

Если вам даже все равно, конвертируются ли типы в Vertex до тех пор, покапоскольку они имеют одинаковые члены, вы можете даже пропустить присваивание - аргументы шаблона C ++ по существу работают с использованием duck typing ;если вы сделаете v1.x, а T содержит элемент с именем x, тогда он будет работать, независимо от того, какой тип T может быть на самом деле.

Вы можете быть немного более изощренным, используя boost библиотека признаков типа и статическое утверждение ;с помощью этого вы можете начать определять утверждение, чтобы немного легче понять ошибку:

template <typename T> addTri( T v1, T v2, T v3 )
{
    BOOST_STATIC_ASSERT_MSG(boost::is_convertible<T&, Vertex&>::value,
        "Template argument must be a subclass of Vertex");
    Vertex &v1r = v1;
    // ....
}
4 голосов
/ 27 августа 2011

Комбинация enable_if, is_base_of и is_convertible типографских текстов должна сделать работу:

template <typename T>
struct Foo : public std::enable_if<std::is_base_of<YourBase, T>::value &&
                                   std::is_convertible<T&, A&>::value,
                    T>::type
{
  // consider "using YourBase::foo;" directives here
};

Типовые черты доступны от <type_traits> в современных компиляторах, или <tr1/type_traits> или Boost в противном случае.

2 голосов
/ 27 августа 2011

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

#include <type_traits>

template <typename T> 
void addTri(T v1, T v2, T v3, char (*)[is_base_of<Vertex, T>::value] = 0)
{
    ...
}

, чтобы отключить генерацию addTri, если T не наследуется от Vertex.Но вам не нужно, чтобы он мог использовать pos член.

Обновление: На самом деле std::is_base_of вернет true, если Vertex является недоступным базовым классом T.Вместо этого используйте следующую реализацию is_base_of:

template <typename B, typename D>
struct is_base_of 
{
    static const bool value = std::is_convertible<D*, B*>::value
        && std::is_class<B>::value;
};
0 голосов
/ 27 августа 2011

Просто используйте ваше первое решение без нечетных :public Vertex. Когда вы создаете экземпляр с Vertex или с чем-то, что имеет pos член, все будет хорошо. C ++ не должен знать, что у каждого T есть член pos. Если вы в любое время создадите экземпляр шаблона с чем-либо, у которого нет члена pos, вы получите ошибку компилятора, в противном случае все будет в порядке.

То, что вы ищете, - это концепции, но я думаю, что они были исключены из стандарта C ++ 0x.

0 голосов
/ 27 августа 2011

Возможно, вы неправильно просматриваете шаблоны. То, что вы описываете, похоже, будет лучше обработано добрым оломодным наследованием. Вместо того, чтобы передавать экземпляры вашего объекта, попробуйте вместо этого передать указатели так:

addTri( Vertex *v1, Vertex *v2, Vertex *v3 )
{
    // Take v1.pos, v2.pos, v3.pos and create a geometric repn..
    Triangle tri( v1->pos, v2->pos, v3->pos ) ; // all vertices will 
    // have to have a .pos member.

    // Create the vertex buffer..
    VertexBuffer<T> vb ...
}

Затем просто передайте указатели на ваши наследуемые объекты (при необходимости используйте родительский класс)

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