6

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 }
Johannes Schaub - litb
  • 496,577
  • 130
  • 894
  • 1,212
Anycorn
  • 50,217
  • 42
  • 167
  • 261
  • 1
    A bit bigger picture would help here. You have to do a bit of design change to get the same effect. Also, the line numbers tend to get in the way. :) – GManNickG Apr 11 '10 at 03:10
  • @GMan I suppose I can use extra default argument, `bool consecutive = _1 == _2 - 1`? – Anycorn Apr 11 '10 at 03:13
  • I'm looking forward to seeing this one answered. It will advance my understanding of the language. – Omnifarious Apr 11 '10 at 03:16
  • 1
    @aaa: What are you hoping to do, though? – GManNickG Apr 11 '10 at 03:18
  • @GMan mapping multidimensional indices from flat index. Consecutive index does not require integer divide I like to avoid – Anycorn Apr 11 '10 at 03:24
  • @aaa: I'm afraid I'm only on the edge of understanding what you meant by that. :) In any case, is this mapping done at run-time or compile-time? And, in suspicion of the former, is Boost available? – GManNickG Apr 11 '10 at 03:30
  • @aaa: An example of how you desire to use this would help. –  Apr 11 '10 at 03:55
  • @Gman I put program listing. I make it sound too complicated, it is not that involved. Cannot use boost runtime functions, this is for GPU device – Anycorn Apr 11 '10 at 04:09
  • 2
    @aaa: Ah, I see. What you have seems to work pretty well, pretty clean too. :) You should post it as an answer and accept it. – GManNickG Apr 11 '10 at 04:16

5 Answers5

4

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 }
Anycorn
  • 50,217
  • 42
  • 167
  • 261
  • 1
    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 Apr 11 '10 at 10:03
  • Depending what `multiply` does, maybe that expression can even be moved into an `enum`. (After eliminating the call, of course.) – Potatoswatter Apr 11 '10 at 13:25
1

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
  • 339,232
  • 124
  • 596
  • 636
1

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
  • 496,577
  • 130
  • 894
  • 1,212
0

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

dicroce
  • 45,396
  • 28
  • 101
  • 140
0

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
  • 73,191
  • 16
  • 130
  • 183
  • 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 :) – Johan Boulé Apr 11 '10 at 03:59