2008-10-23 13 views
6

Ich bin von g++ 3.3 im folgenden Code einen seltsamen Fehler bekommen:C++ zwei oder mehr Datentypen in Deklaration

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

Der Fehler wird wie folgt dar:

 
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 

Es muss sein etwas wirklich albernes, aber ich habe es schon meiner Gummiente und einem Freund vergebens erzählt.

Danke, Lazyweb.

+2

+1 für die Angabe an Ihre Gummiente. – Robert

Antwort

10

Die ausgewählte Antwort von CAdaker oben löst das Problem, erklärt aber nicht warum löst es das Problem.

Wenn eine Funktionsvorlage analysiert wird, findet keine Suche in abhängigen Typen statt. Als Ergebnis können Konstrukte wie die folgenden analysiert werden:

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

Doch dieses „Feature“ hat ihren Preis, und in diesem Fall ist es, dass die Definition von ‚foo‘ Hinweise auf den Inhalt der erfordert Vorlage "B". Wenn ‚foo‘ eine verschachtelte Art von ‚B‘ verwendet, dann ist das typename Schlüsselwort erforderlich, um den Compiler zu sagen, dass der Name ein Typ ist:

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 
} 

Ohne ‚Typnamen‘ in der über dem Compiler, dass X nimmt an ist ein Objekt (oder eine Funktion).

Und falls ein Mitglied Funktion aufgerufen wird und der Anruf hat explizite Template-Argumente dann muss der Compiler weiß die < als Beginn einer Vorlage Argumentliste und nicht weniger als Betreiber behandeln:

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 
} 

Ohne template geht der Compiler davon aus, dass < der Kleiner-als-Operator ist, und generiert daher den Syntaxfehler, wenn er int> sieht, da dies kein Ausdruck ist.

Diese Hinweise sind erforderlich sogar, wenn die Definition der Vorlage sichtbar ist. Der Grund dafür ist, dass eine explizite Spezialisierung später möglicherweise die tatsächlich gewählte Definition ändern kann:

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

Verwenden Sie entweder nur

original.to_string(); 

oder, wenn Sie wirklich die Typdeklarierer benötigen,

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

Die to_string hat in diesem Fall keine Standardspezifikation, aber Ihre letzte Antwort funktioniert! Vielen Dank. – cdleary

2

Die folgenden für mich zusammengestellt (mit 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; 
} 
+0

Ja, aber es wird nicht kompiliert, wenn Sie tatsächlich die Funktion aufrufen und die Template-Parameter auswerten. – cdleary

+0

#include hinzufügen und main zu diesem kompilieren (mit gcc 4.0.1): int main() { bitset <4> orig; orig.set (0,0); Orig.Satz (1,1); orig.set (2,0); Orig.Satz (3,1); Bitset <2> Bits = Schnitt_bitset <2,4> (orig, 2); cout << bits.to_string() << endl; Rückgabe 0; } Welchen Fehler bekommen Sie? –

+0

Ich bekomme den gleichen Fehler wie oben. Ich benutze g ++ 3.3 jedoch - sie haben möglicherweise die stdlib in g ++ aktualisiert, um einen Standard-Template-Parameter in 3.4 zu enthalten, aber cplusplus.com sagt "sie werden nicht implizit vom Compiler abgeleitet." (http://www.cplusplus.com/reference/stl/bitset/to_string.html) – cdleary

Verwandte Themen