Шаблоны C ++: вычисляйте значения и принимайте решения во время компиляции - PullRequest
3 голосов
/ 15 сентября 2010

Скажем, у вас есть векторный класс, который имеет длину и тип шаблона, т.е. vec<2,float>. Они также могут быть вложенными - vec<2,vec<2,vec<2,float> > > или vec<2,vec<2,float> >. Вы можете рассчитать, насколько глубоко вложенный один из этих векторов выглядит так:

template<typename T>
inline int depth(const T& t) { return 0; }
template<int N, typename T>
inline int depth(const vec<N,T>& v) { return 1+depth(v[0]); }

Беда в том, что вы не будете знать, насколько она глубока до времени выполнения, но вам может понадобиться узнать глубину во время компиляции, чтобы сделать что-то вроде этого:

// Do this one when depth(v1) > depth(v2)
template<int N, typename T, int M, typename U>
inline vec<N,T> operator +(const vec<N,T>& v1, const vec<M,U>& v2) {
    return v1 + coerce(v2,v1);
}
// Do this one when depth(v1) < depth(v2)
template<int N, typename T, int M, typename U>
inline vec<M,U> operator +(const vec<N,T>& v1, const vec<M,U>& v2) {
    return coerce(v1,v2) + v2;
}

Вы не можете просто добавить оператор if, потому что (a), который глубже влияет на тип возвращаемого значения, и (b) coerce () генерирует ошибку сборки, если вы пытаетесь привести вложенный вектор к менее вложенному. один.

Возможно ли сделать что-то подобное или я столкнулся с ограничениями шаблонов C ++?

Ответы [ 3 ]

5 голосов
/ 15 сентября 2010

Это вполне возможно. Попробуйте например

template<int N, typename T, int M, typename U>
inline typename enable_if<is_deeper<T, U>::value, vec<N,T> >::type 
operator +(const vec<N,T>& v1, const vec<M,U>& v2) {
    return v1 + coerce(v2,v1);
}

template<int N, typename T, int M, typename U>
inline typename enable_if<is_deeper<U, T>::value, vec<M,U> >::type 
operator +(const vec<N,T>& v1, const vec<M,U>& v2) {
    return coerce(v1,v2) + v2;
}

Где is_deeper это что-то вроде

/* BTW what do you want to do if none is deeper? */
template<typename T, typename U>
struct is_deeper { static bool const value = false; };

template<typename T, int N, typename U>
struct is_deeper<vec<N, U>, T> { 
  static bool const value = true;
};

template<typename T, int N, typename U>
struct is_deeper<T, vec<N, U> > { 
  static bool const value = false;
};

template<typename T, int N, int M, typename U>
struct is_deeper<vec<M, T>, vec<N, U> > : is_deeper<T, U> 
{ };
3 голосов
/ 15 сентября 2010

Шаблон метапрограммирования освободит вас. Я делаю это во время выполнения, но это оценивается во время компиляции:

  #include <iostream>
#include <boost\static_assert.hpp>
using namespace std;

template<size_t Depth> class Vec
{
public:
 enum {MyDepth = Vec<Depth-1>::MyDepth + 1};
};

template<> class Vec<1>
{
public:
 enum {MyDepth = 1};
};

  BOOST_STATIC_ASSERT(Vec<12>::MyDepth == 12);
//  Un-commenting the following line will generate a compile-time error
//    BOOST_STATIC_ASSERT(Vec<48>::MyDepth == 12);

int main()
{
 cout << "v12 depth = " << Vec<12>::MyDepth;
}

РЕДАКТИРОВАТЬ: Включено усиление статического утверждения, чтобы продемонстрировать, как это оценивается во время компиляции.

2 голосов
/ 15 сентября 2010

Частичная специализация очень полезна для самоанализа. Обычно лучше избегать inline функций с постоянными результатами времени компиляции. (C ++ 0x может немного облегчить это, но я не уверен, насколько).

Во-первых, ваш vec шаблон очень похож на boost::array / std::tr1::array / std::array, поэтому я просто назову его array.

template< class ArrT >
struct array_depth; // in the general case, array depth is undefined

template< class ElemT, size_t N > // partial specialization
struct array_depth< array< ElemT, N > > { // arrays do have depth
    enum { value = 0 }; // in the general case, it is zero
};

template< class ElemT, size_t N1, size_t N2 > // more specialized than previous
struct array_depth< array< array< ElemT, N1 >, N2 > {
    enum { value = 1 + array_depth< array< ElemT, N1 > >::value }; // recurse
};

// define specializations for other nested datatypes, C-style arrays, etc.
// C++0x std::rank<> already defines this for C-style arrays
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...