2013-09-19 3 views
0

У меня возникла проблема, когда я хочу специализировать функцию члена шаблона класса шаблона в приведенном ниже коде. Ответ на этот вопрос explicit specialization of template class member function, по-видимому, предполагает, что это невозможно. Это правильно, и если да, то есть ли какая-нибудь работа, которую я могу использовать, чтобы функции inline inc расширялись во время компиляции?C++ template class member function specialization

Большое спасибо!

#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 ++ выплевывает:

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]

+0

Если ваш компилятор поддерживает C++ 11, вы можете использовать 'static_assert'. Кроме того, вы можете вызвать экземпляр второго шаблона (независимо от 'IdxIterator') внутри' inc', который выполняет эту проверку. – dyp

+0

Просто попытайтесь свести к минимуму код, который вы задали в своих вопросах !!! Большая часть материала здесь не имеет отношения к проблеме вообще. – iavr

+0

Это кажется довольно тривиальным, если ваша единственная проблема заключается в обеспечении положительного значения. 'template void foo() {/ * impl * /}' –

ответ

2

Там может быть лучше в C++ 11, но вы всегда можете пойти по перегрузке вместо специализации:

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>()); }; 
}; 
+0

Для ответа на этот вопрос понадобилась бы специализация для 'template <> num <0> {}' иначе компилятор не будет знать, когда прекращать работу при вызове ' номер .' –

0

Вы можете сделайте то, что предлагает сообщение об ошибке компилятора:

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

, т.е. переместите определение в область пространства имен.

0

Создать вспомогательный-структуру за пределами класса

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*/); 
    } 

}; 

Примечание, если вы используете GCC вы можете __attribute__((always_inline)) принуждать встраивание.