C++ два или более типов данных в объявлении

Я получаю странную ошибку от g++ 3.3 в следующем коде:

#include <bitset>
#include <string>

using namespace std;

template <int N, int M>
bitset<N> slice_bitset(const bitset<M> &original, size_t start) {
    string str = original.to_string<char, char_traits<char>, allocator<char> >();
    string newstr = str.substr(start, N);
    return bitset<N>(newstr);
}

int main() {
    bitset<128> test;
    bitset<12> result = slice_bitset<12, 128>(test, 0);
    return 0;
}

Ошибка заключается в следующем:

In function `std::bitset slice_bitset(const std::bitset&, unsigned int)':
syntax error before `,' token
`char_traits' specified as declarator-id
two or more data types in declaration of `char_traits'
`allocator' specified as declarator-id
two or more data types in declaration of `allocator'
syntax error before `>' token

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

Спасибо, Лазивеб.


person cdleary    schedule 23.10.2008    source источник
comment
+1 за то, что рассказал об этом своей резиновой утке.   -  person Robert    schedule 03.12.2009


Ответы (3)


Выбранный ответ из CAdaker выше решает проблему, но не объясняет, почему это решает проблему.

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

template <typename T>
class B;

template <typename T>
void foo (B<T> & b) {
  // Use 'b' here, even though 'B' not defined
}

template <typename T>
class B
{
  // Define 'B' here.
};

Однако эта «функция» имеет свою цену, и в данном случае она заключается в том, что определение «foo» требует подсказок о содержимом шаблона «B». Если 'foo' использует вложенный тип 'B', то ключевое слово typename требуется, чтобы сообщить компилятору, что имя является типом:

template <typename T>
void foo (B<T> & b)
{
  typename B<T>::X t1;    // 'X' is a type - this declares t1
  B<T>::Y * t1;           // 'Y' is an object - this is multiplication
}

Без 'typename' в приведенном выше компиляторе будет считаться, что X является объектом (или функцией).

Точно так же, если вызывается функция-член и вызов имеет явные аргументы шаблона, то компилятор должен знать, что следует обрабатывать < как начало списка аргументов шаблона, а не как оператор «меньше чем»:

template <typename T>
void foo (B<T> & b)
{
  b.template bar<int> (0); // 'bar' is a template, '<' is start of arg list
  b.Y < 10;                // 'Y' is an object, '<' is less than operator
}

Без template компилятор предполагает, что < является оператором меньше, и поэтому генерирует синтаксическую ошибку, когда видит int>, поскольку это не выражение.

Эти подсказки необходимы, даже когда видно определение шаблона. Причина в том, что явная специализация может позже изменить определение, которое фактически выбрано:

template <typename T>
class B
{
  template <typename S>
  void a();
};

template <typename T>
void foo (B<T> & b)
{
  b.a < 10;            // 'B<int>::a' is a member object
}

template <>
class B<int>
{
  int a;
};
person Richard Corden    schedule 27.10.2008

Используйте либо просто

original.to_string();

или, если вам действительно нужны спецификаторы типа,

original.template to_string<char, char_traits<char>, allocator<char> >();
person CAdaker    schedule 23.10.2008
comment
В этом случае to_string не имеет спецификации по умолчанию, но ваш последний ответ работает! Спасибо. - person cdleary; 24.10.2008

Для меня скомпилировано следующее (с использованием gcc 3.4.4):

#include <bitset>
#include <string>

using namespace std;

template <int N, int M> 
bitset<N> slice_bitset(const bitset<M> &original, size_t start) 
{   
  string str = original.to_string();
  string newstr = str.substr(start, N);    
  return bitset<N>(newstr);
}

int main() 
{ 
  return 0; 
}
person Tim Stewart    schedule 23.10.2008
comment
Да, но он не скомпилируется, если вы на самом деле вызовете функцию и оцените параметры шаблона. - person cdleary; 24.10.2008
comment
Добавляем #include ‹iostream› и меняем main на этот скомпилированный (с gcc 4.0.1): int main() { bitset‹4› orig; исходный набор (0,0); исходный набор (1,1); исходный набор (2,0); исходный набор (3,1); набор битов‹2› биты = slice_bitset‹2,4›(orig, 2); cout ‹‹ bits.to_string() ‹‹ endl; вернуть 0; } Какую ошибку вы получаете? - person Tim Stewart; 24.10.2008
comment
Я получаю ту же ошибку, что и выше. Однако я использую g++ 3.3 - они, возможно, обновили stdlib в g++, чтобы включить параметр шаблона по умолчанию в 3.4, но cplusplus.com говорит, что компилятор не выводит их неявно. (cplusplus.com/reference/stl/bitset/to_string.html ) - person cdleary; 25.10.2008