Sunday, February 13, 2011

C++ two or more data types in declaration

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.

  • Use either just

    original.to_string();
    

    or, if you really need the type specifiers,

    original.template to_string<char, char_traits<char>, allocator<char> >();
    
    cdleary : The to_string has no default specification in this case, but your latter answer works! Thanks.
    From CAdaker
  • 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; 
    }
    
    cdleary : Yeah, but it won't compile if you actually call the function and evaluate the template parameters.
    Tim Stewart : Adding #include and changing main to this compiled (with gcc 4.0.1): int main() { bitset<4> orig; orig.set(0,0); orig.set(1,1); orig.set(2,0); orig.set(3,1); bitset<2> bits = slice_bitset<2,4>(orig, 2); cout << bits.to_string() << endl; return 0; } What error are you getting?
    cdleary : I get the same error as above. I am using g++ 3.3, however -- they may have updated the stdlib in g++ to include a default template parameter in 3.4, but cplusplus.com says "they are not implicitly deduced by the compiler." (http://www.cplusplus.com/reference/stl/bitset/to_string.html)
  • 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;
    };
    

0 comments:

Post a Comment