2015-08-27 3 views
0

Следующий код вызывает ошибки компилятора, но только для gcc (до 5.2) и clang (до 3.7). VS2015 компилируется без проблемов. (Для г ++ вы должны использовать опцию -std = C++ 14)Пакет параметров шаблона C++ от одного вариационного шаблона к другому вызывает ошибку компилятора

//************************************************ 
template <int... items> 
struct Sequence { 
//************************************************ 
public: 
    enum { size = sizeof...(items) }; 
    operator int() const { return data[rank - 1]; } 
    Sequence& operator=(const Sequence& s) { rank = s.rank; return *this; } 
    int get_rank() const { return rank; } 
    bool first() { rank = 1; return true; } 
    bool last() { rank = size; return true; } 
    bool next() { return (rank < size) ? ++rank, true : false; } 
    bool prev() { return (rank > 1) ? --rank, true : false; } 
    bool is_first() { return rank == 1; } 
    bool is_last() { return rank == size; } 
protected: 
    static const int data[sizeof... (items)]; 
    int rank = 1; 
}; 

template <int... items> 
const int Sequence<items...>::data[sizeof...(items)] = { items... }; 


//************************************************ 
template <unsigned N, template <unsigned> class F, int... items> 
struct generate_sequence { 
//************************************************ 
    typedef typename generate_sequence<N - 1, F, F<N>::value, items...>::result result; 
}; 

//************************************************ 
template <template <unsigned> class F, int... items> 
struct generate_sequence<0, F, items...> { 
//************************************************ 
    typedef Sequence<F<0>::value, items...> result; 
}; 


//************************************************ 
template <int... coeffs> 
struct polynomial { 
//************************************************ 
    template <int var, int a0, int... ai> struct ipoly { enum { value = a0 + var * ipoly<var, ai...>::value }; }; 
    template <int var, int a0> struct ipoly<var, a0> { enum { value = a0 + 0 * var }; }; 

    template <unsigned index> 
    class number_generator { public: enum { value = ipoly<index + 1, coeffs...>::value }; }; 
}; 


//************************************************ 
template <unsigned N> 
class NaturalNumbers : public generate_sequence<N - 1, polynomial<0,1>::number_generator>::result {}; 
//************************************************ 

//************************************************ 
template <unsigned N, int... coeffs> 
class PolynomialNumbers : public generate_sequence<N - 1, polynomial<coeffs...>::number_generator>::result {}; 
//************************************************ 

int main() { 
    NaturalNumbers<10> nn; 
    PolynomialNumbers<10,0,1> pn; 
} 

Выход компилятора выглядит следующим образом:

bug.cpp:59:98: error: type/value mismatch at argument 2 in template parameter list for 'template<unsigned int N, template<unsigned int <anonymous> > class F, int ...items> struct generate_sequence' 
class PolynomialNumbers : public generate_sequence<N - 1, polynomial<coeffs...>::number_generator>::result {}; 
                           ^
bug.cpp:59:98: note: expected a class template, got 'polynomial<coeffs ...>::number_generator' 
bug.cpp:59:101: error: expected '{' before 'result' 
class PolynomialNumbers : public generate_sequence<N - 1, polynomial<coeffs...>::number_generator>::result {}; 
                            ^
bug.cpp: In function 'int main()': 
bug.cpp:64:27: error: non-template type 'PolynomialNumbers' used as a template 
    PolynomialNumbers<10,0,1> pn; 
         ^

Является ли это ошибка компилятора или код как-то не так? Для меня ключ лежит в строке

ожидается шаблон класса, получил «полиномом :: number_generator»

выхода компилятора. Компилятор, очевидно, не понимает, что «polyomial :: number_generator» на самом деле является шаблоном. Что вы имеете в виду?

ответ

1

Поскольку number_generator является зависит имя, вы должны префикс с template ключевого слова:

template <unsigned N, int... coeffs> 
class PolynomialNumbers 
: public generate_sequence< 
     N - 1, 
     polynomial<coeffs...>::template number_generator 
          // ^^^^^^^^ 
     >::result 
{}; 

В качестве побочного сведению, что может быть лучше, чтобы избежать передачи шаблона в любом месте и попытаться переписать ваш number_generator быть более похожим на класс metafunction:

class number_generator { 
public: 
    template <unsigned index> 
    using apply = ipoly<index + 1, coeffs...>; 
}; 

Это сделает весь ваш код проще, так как типы являются гражданами первого класса и что-й at не является типом (т.е. шаблон шаблона или значение) гораздо труднее справиться.