views:

308

answers:

5

hello

I am trying to specialize template the following way:

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
};

however I get compiler message error

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

what do my doing wrong? thanks

I put workaround in comments. Apparently I cannot do arithmetic in template specialization? seems counterintuitive.

here is my final solution in the problem to be solved. Basically, consecutive index requires one multiplication only.

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  A: 

Try something like this:

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

template<size_t _1>
struct integral_index_2 : public integral_index_<_1, _1+1> {
};
Brian R. Bondy
I am trying to specialize cases where second argument is one greater than first
aaa
Then he loses the effect he wanted.
GMan
@aaa: That won't work.
Dietrich Epp
@aaa: See edit.
Brian R. Bondy
helloI just put something similar using third template parameter in the original post
aaa
A: 

I think the problem is that your attempting to specialize by value instead of type...

dicroce
You can specialize by value. The problem is the arithmetic within the specialization.
GMan
A: 

Here's something that works for me: use a default argument for _2 instead of trying to specialize.

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

Does that look like what you want?

Chris Lutz
aaa really wants to write a specialized version of the template, not just a default argument.Anyway, he already found a nice workaround with the "bool consecutive = (_1 == _2 - 1)" trick :)
bohan
+4  A: 

I am posting my solution is suggested by 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 }
aaa
You can get rid of the static `eval` and just make the value an actual static variable. That way you can access the value as a nested `::value` rather than calling a function (that still happens at runtime).
Dean Michael
Depending what `multiply` does, maybe that expression can even be moved into an `enum`. (After eliminating the call, of course.)
Potatoswatter
+1  A: 

You can also move the condition from the primary template into the specialization. The trick is that while non-type parameters in sub-expressions aren't allowed in non-type specialization arguments, they are allowed in type arguments

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
};

Occassionally, people also use SFINAE for this. The following accesses ::type which is only there if the condition is true. If it is false, the type is not there and SFINAE sorts out the specialization.

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
};

With enable_if being the following well-known template

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

template<typename R = void>
struct enable_if<true, R> { typedef R type; };
Johannes Schaub - litb