user2762038
user2762038

Reputation: 29

c++ template class member function specialization

I have a problem where I want to specialize a template member function of a template class in the code below. The answer to this question explicit specialization of template class member function seems to suggest that it can't be done. Is that correct, and if so, is there any work around I can use so that by inline inc functions get expanded at compile time?

Many thanks!

#include <iostream>
#include <cstdio>

template <class IT, unsigned int N>
struct IdxIterator {
private:
  int startIdx[N], endIdx[N];  
  int curIdx[N];
  IT iter;

public:
  IdxIterator(IT it, int cur[], int start[], int end[]): iter(it) {
    for (int i = 0; i < N; i++) {
      curIdx[i] = cur[i];
      startIdx[i] = start[i];
      endIdx[i] = end[i];
    }
  }

  template <int dim>
  inline void inc() {
    curIdx[dim]++;
    if (curIdx[dim] > endIdx[dim]) {
      if (dim > 0) {
        curIdx[dim] = startIdx[dim];
        inc<dim-1>();
      }
    }
  }

  // how to declare this specialization?
  template <> template <>
  inline void inc<-1>() {
    std::cerr << "IdxIterator::inc(" << -1 << ") dim out of bounds!\n";
    throw 1;
  }

  inline IdxIterator<IT, N> operator++() {
    iter++;
    inc<N-1>();
    return *this;
  }

};

int main(int argc, char** argv) {

  int *buf = new int[100];
  int start[1], end[1];
  start[0] = 0; end[0] = 99;
  IdxIterator<int*, 1> it(buf, start, start, end);
  ++it;

  return 0;

}

G++ spits out:

test2.cpp:32:13: error: explicit specialisation in non-namespace scope ‘struct IdxIterator’ test2.cpp:32:25: error: explicit specialisation in non-namespace scope ‘struct IdxIterator’ test2.cpp:33:23: error: template-id ‘inc<-0x00000000000000001>’ in declaration of primary template test2.cpp: In member function ‘void IdxIterator::inc() [with int dim = -0x000000000000003fe, IT = int*, unsigned int N = 1u]’: test2.cpp:27:9: error: template instantiation depth exceeds maximum of 1024 (use -ftemplate-depth= to increase the maximum) instantiating ‘void IdxIterator::inc() [with int dim = -0x000000000000003ff, IT = int*, unsigned int N = 1u]’ test2.cpp:27:9: recursively instantiated from ‘void IdxIterator::inc() [with int dim = -0x00000000000000001, IT = int*, unsigned int N = 1u]’ test2.cpp:27:9: instantiated from ‘void IdxIterator::inc() [with int dim = 0, IT = int*, unsigned int N = 1u]’ test2.cpp:41:5: instantiated from ‘IdxIterator IdxIterator::operator++() [with IT = int*, unsigned int N = 1u]’ test2.cpp:53:5: instantiated from here

test2.cpp: At global scope: test2.cpp:22:15: warning: inline function ‘void IdxIterator::inc() [with int dim = -0x000000000000003ff, IT = int*, unsigned int N = 1u]’ used but never defined [enabled by default]

Upvotes: 0

Views: 1477

Answers (3)

Joseph Franciscus
Joseph Franciscus

Reputation: 371

Create a helper struct outside of class

template<dim>
struct inc {
template<class cur, end>
      inline static void foo(cur curIdx, end endIdx) {
        curIdx[dim]++;
    if (curIdx[dim] > endIdx[dim]) {
        inc<dim-1>::foo(curIdx, endIdx);
      }
    }    
};

template<>
struct inc<0> {
    template<class cur, end>
      inline static void foo(cur, end) {
       //terminate
    }    
};

class IdxIterator {
       template<int i>
       void inc() {
        static_assert(i > 0, "error out of bounds");
         int<i>::foo(/*params*/); 
    }

};

Note if you are using the GCC you may __attribute__((always_inline))to force inlining.

Upvotes: 0

Tom
Tom

Reputation: 7992

You can do what the compiler error message suggests:

template <class IT, unsigned int N>
struct IdxIterator {
private:
  template <int dim>
  inline void inc() {
    curIdx[dim]++;
    if (curIdx[dim] > endIdx[dim]) {
      if (dim > 0) {
        curIdx[dim] = startIdx[dim];
        inc<dim-1>();
      }
    }
  }
};

template <> template <>
inline void IdxIterator::inc<-1>() {
  std::cerr << "IdxIterator::inc(" << -1 << ") dim out of bounds!\n";
  throw 1;
}

ie move the definition to namespace-scope.

Upvotes: 0

iavr
iavr

Reputation: 7647

There may be a better way in C++11, but you can always go via overloading instead of specialization:

template <int N>
struct num { };

class A
{
    template <int N>
    void f(num <N>) { };

    void f(num <-1>) { };

public:
    template <int N>
    void f() { f(num <N>()); };
};

Upvotes: 2

Related Questions