Question

I'm getting a strange error from g++ 3.3 in the following code:

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

The error is as follows:

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

It has to be something really silly, but I've already told it to my rubber duck and a friend to no avail.

Thanks, Lazyweb.

Was it helpful?

Solution

The selected answer from CAdaker above solves the problem, but does not explain why it solves the problem.

When a function template is being parsed, lookup does not take place in dependent types. As a result, constructs such as the following can be parsed:

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

However, this "feature" has a cost, and in this case it is that the definition of 'foo' requires hints on the contents of the template 'B'. If 'foo' uses a nested type of 'B', then the typename keyword is required to tell the compiler that the name is a type:

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
}

Without 'typename' in the above the compiler will assume that X is an object (or function).

Similarly, if a member function is called and the call has explicit template arguments then the compiler needs to know to treat the < as the start of a template argument list and not the less than operator:

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
}

Without template, the compiler assumes that < is the less than operator, and so generates the syntax error when it sees int> since that is not an expression.

These hints are required even when the definition of the template is visible. The reason is that an explicit specialization might later change the definition that is actually chosen:

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

OTHER TIPS

Use either just

original.to_string();

or, if you really need the type specifiers,

original.template to_string<char, char_traits<char>, allocator<char> >();

The following compiled for me (using 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; 
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top