C ++ Шаблон Метапрограммирование Специализация Неоднозначность - PullRequest
2 голосов
/ 28 октября 2011

Итак, я только начинаю с шаблонного метапрограммирования и пишу строковый класс.Я реализовал ToString, Concat, CharAt и Length без особых проблем, связанных с шаблонами.Я пытался реализовать Substring следующим образом:

struct Null;

// String class definition
template <char C, class S>
struct String {
  static const char chr = C;
  typedef S tail;
};

// Substring
// Gets the substring of length L starting at index I from string S.
template <int I, int L, class S>
struct Substring;

template <class S>
struct Substring<0, 0, S> {
  typedef Null substr;
};

// Will also cover I < 0 case
template <int I, int L>
struct Substring<I, L, Null> {
  typedef Null substr;
};

template <int L, char C, class S>
struct Substring<0, L, String<C, S> > {
  typedef String<C, typename Substring<0, L-1, S>::substr> substr;
};

template <int I, int L, char C, class S>
struct Substring<I, L, String<C, S> > {
  typedef typename Substring<I-1, L, S>::substr substr;
};

int main() {
  // This all works...
  typedef String<'H', String<'e', String<'l', String<'l',
            String<'o', Null> > > > > hello;
  typedef String<',', String<' ', Null> > comma;
  typedef String<'w', String<'o', String<'r', String<'l', String<'d',
            String<'!', Null> > > > > > world;
  typedef Concat<hello, Concat<comma, world>::newstr>::newstr hello_world;
  // ...up to here.
  typedef Substring<3, 5, hello_world>::substr mystr;
  return 0;
}

Когда я компилирую, я получаю ошибку неоднозначности:

template.cpp:161: error: ambiguous class template instantiation for ‘struct
    Substring<0, 0, String<'o', String<'r', String<'l', String<'d', String<'!',
    Null> > > > > >’
template.cpp:149: error: candidates are: struct Substring<0, 0, S>
template.cpp:160: error:                 struct Substring<0, L, String<C, S> >
template.cpp:165: error:                 struct Substring<I, L, String<C, S> >
template.cpp:161: error: invalid use of incomplete type ‘struct Substring<0, 0, 
    String<'o', String<'r', String<'l', String<'d', String<'!', Null> > > > > >’
template.cpp:146: error: declaration of ‘struct Substring<0, 0, String<'o',
    String<'r', String<'l', String<'d', String<'!', Null> > > > > >’
template.cpp: In function ‘int main()’:
template.cpp:197: error: template argument 1 is invalid

Я немного запутался.Я думал, что весь смысл специализации на шаблонах заключается в том, чтобы делать такие вещи.Почему это не просто продолжение чего-то вроде:

template <int N>
struct Foo { ... }

template <>
struct Foo<0> { ... }

Как мне исправить эту неоднозначность?

Спасибо.

1 Ответ

6 голосов
/ 28 октября 2011

Здесь вы определяете Substring с 0, 0 и любым class S:

template <class S>
struct Substring<0, 0, S> {
  typedef Null substr;
};

Здесь вы определяете Substring с I, L и String< C, S >:

template <int I, int L, char C, class S>
struct Substring<I, L, String<C, S> > {
  typedef typename Substring<I-1, L, S>::substr substr;
};

Никто не является лучшим кандидатом, чем другой, поскольку один лучше подходит для I, L, но хуже для String< C, S >. Если вы объявите первый случай как:

template <char C, class S>
struct Substring<0, 0, String< C, S > > {
  typedef Null substr;
};

Тогда это будет более специализированным, чем любой другой. Однако в вашем коде могут быть другие источники неоднозначности.

...