C ++ два или более типов данных в объявлении - PullRequest
6 голосов
/ 24 октября 2008

Я получаю странную ошибку от 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

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

Спасибо, Lazyweb.

Ответы [ 3 ]

10 голосов
/ 27 октября 2008

Выбранный ответ из 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;
};
7 голосов
/ 24 октября 2008

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

original.to_string();

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

original.template to_string<char, char_traits<char>, allocator<char> >();
2 голосов
/ 24 октября 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; 
}
...