2010-04-11 10 views
6

Estoy tratando de especializarse plantilla de la siguiente manera:C++ parámetro de plantilla no tipológicas aritmética

template<size_t _1,size_t _2> // workaround: bool consecutive = (_1 == _2 - 1)> 
struct integral_index_ {}; 
... 
template<size_t _1> 
struct integral_index_<_1, _1 + 1> { // cannot do arithmetic? 
//struct integral_index_<_1, _2, true> { workaround 
}; 

sin embargo me sale mensaje de error del compilador

the template argument list of the partial specialization includes a non 
-type argument whose type depends on a template parameter. 

¿qué mi haciendo mal? gracias

Puse la solución en los comentarios. Aparentemente, no puedo hacer aritmética en la especialización de plantillas. parece contradictorio.

he aquí mi solución final en el problema por resolver. Básicamente, el índice consecutivo requiere una multiplicación solamente.

130 template<size_t _1,size_t _2, bool consecutive = (_1 == _2 - 1)> 
131 struct integral_index_ { 
132  template<typename T, typename U> 
133  __device__ 
134  static T eval(const T (&N)[4], const U &index) { 
135   T j = index/N[_1]; 
136   return ((index - j*N[_1])*range<0,_1>::multiply(N) + 
137     j*range<0,_2>::multiply(N)); 
138  } 
139 }; 
140 
141 template<size_t _1,size_t _2> 
142 struct integral_index_<_1, _2, true> { 
143  template<typename T, typename U> 
144  __device__ 
145  static T eval(const T (&N)[4], const U &index) { 
146   return index*range<0,_1>::multiply(N); 
147  } 
148 }; 
149 
150 template<size_t _1,size_t _2, typename T, typename U> 
151 __device__ 
152 T integral_index(const T (&N)[4], const U &index) { 
153  return integral_index_<_1,_2>::eval(N, index); 
154 } 
+1

imagen un poco más grande que ayudaría aquí. Tienes que hacer un poco de cambio de diseño para obtener el mismo efecto. Además, los números de línea tienden a interponerse en el camino. :) – GManNickG

+0

@GMan Supongo que puedo usar un argumento predeterminado adicional, 'bool consecutivo = _1 == _2 - 1'? – Anycorn

+0

Estoy deseando ver esta respuesta. Avanzará mi comprensión del idioma. – Omnifarious

Respuesta

4

Estoy publicar mi solución es sugerido por GMan

130 template<size_t _1,size_t _2, bool consecutive = (_1 == _2 - 1)> 
131 struct integral_index_ { 
132  template<typename T, typename U> 
133  __device__ 
134  static T eval(const T (&N)[4], const U &index) { 
135   T j = index/N[_1]; 
136   return ((index - j*N[_1])*range<0,_1>::multiply(N) + 
137     j*range<0,_2>::multiply(N)); 
138  } 
139 }; 
140 
141 template<size_t _1,size_t _2> 
142 struct integral_index_<_1, _2, true> { 
143  template<typename T, typename U> 
144  __device__ 
145  static T eval(const T (&N)[4], const U &index) { 
146   return index*range<0,_1>::multiply(N); 
147  } 
148 }; 
149 
150 template<size_t _1,size_t _2, typename T, typename U> 
151 __device__ 
152 T integral_index(const T (&N)[4], const U &index) { 
153  return integral_index_<_1,_2>::eval(N, index); 
154 } 
+1

Puede deshacerse del 'eval' estático y simplemente hacer que el valor sea una variable estática real. De esta forma, puede acceder al valor como ':: value" anidado en lugar de llamar a una función (que aún ocurre en el tiempo de ejecución). –

+0

Dependiendo de lo que 'multiply' haga, tal vez esa expresión incluso se pueda mover a un' enum'. (Después de eliminar la llamada, por supuesto) – Potatoswatter

1

intentar algo como esto:

template<size_t _1,size_t _2> 
struct integral_index_ {}; 

template<size_t _1> 
struct integral_index_2 : public integral_index_<_1, _1+1> { 
}; 
+0

Estoy tratando de especializar casos donde el segundo argumento es uno mayor que el primero – Anycorn

+0

Luego pierde el efecto que quería. – GManNickG

+0

@aaa: Eso no funcionará. –

0

Creo que el problema es que su intento especializarse por valor en lugar del tipo ...

+2

Puede especializarse por valor. El problema es la aritmética dentro de la especialización. – GManNickG

0

Aquí hay algo que funciona para mí: utilizar una argumento predeterminado para _2 en lugar de intentar especializarse.

template <size_t _1, size_t _2 = _1 + 1> 
struct integral_index_ {}; 

¿Eso se parece a lo que quieres?

+0

aaa realmente quiere escribir una versión especializada de la plantilla, no solo un argumento predeterminado. De todos modos, ya encontró una buena solución con el truco "bool consecutive = (_1 == _2 - 1)" :) –

1

También puede mover la condición de la plantilla primaria en la especialización. El truco es que mientras que los parámetros no-Type en sub-expresiones no están permitidos en los argumentos de especialización no de tipo, que se permitidos en argumentos de tipo

template<bool C> struct bool_ { }; 

template<int _1, int _2, typename = bool_<true> > 
struct mapping { 
    // general impl 
}; 

template<int _1, int _2> 
struct mapping<_1, _2, bool_<(_1 + 1) == _2> > { 
    // if consecutive 
}; 

template<int _1, int _2> 
struct mapping<_1, _2, bool_<(_1 * 3) == _2> > { 
    // triple as large 
}; 

Ocasionalmente, las personas también utilizan SFINAE para esto. Los siguientes accesos ::type que solo está allí si la condición es verdadera. Si es falso, el tipo no está allí y SFINAE clasifica la especialización.

template<int _1, int _2, typename = void> 
struct mapping { 
    // general impl 
}; 

template<int _1, int _2> 
struct mapping<_1, _2, 
       typename enable_if<(_1 + 1) == _2>::type> { 
    // if consecutive 
}; 

template<int _1, int _2> 
struct mapping<_1, _2, 
       typename enable_if<(_1 * 3) == _2>::type> { 
    // triple as large 
}; 

Con enable_if ser el siguiente conocido plantilla

template<bool C, typename R = void> 
struct enable_if { }; 

template<typename R = void> 
struct enable_if<true, R> { typedef R type; }; 
Cuestiones relacionadas