假设您有一个具有模板长度和类型的矢量类 - 即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 ++模板的限制?
答案 0 :(得分:5)
完全有可能。试试例子
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>
{ };
答案 1 :(得分:3)
模板元编程将让您自由。我在运行时这样做,但它在编译时进行了评估:
#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;
}
编辑:包含一个boost static assert来演示如何在编译时评估它。
答案 2 :(得分:2)
部分专业化对于内省非常有用。通常最好避免使用编译时常量结果的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