compiler findet template fnk. nicht
-
Bei Templates müssen die Funktionen/Methoden gleich in der Header definiert werden (in deinem Fall die 'string_fnc.h'), andernfalls gibt es wie du schon gesehen hast, einen Linkererror. Folgende Referenz sagt dir auch, warum man Templates in einer Datei definieren muss:
http://titanos.de/iso-c++/cpp:templ_linkUnd vermeide generell das using namespace in Headern, da es sich auf alle Dateien ausweitet, die deine Header inkludieren. So kann es im Zweifelsfall zu Scope-Konflikten kommen. Immer nur in der *.cpp Datei einsetzen.
-
solito schrieb:
...
Templates müssen immer komplett im Header stehen (alternativ die cpp includen... Wenn man sowas macht, schreibt man aber die Templates möglicht in einen separaten Header und Sourcefile, und in der Regel wird der Sorcefile nicht mit der Dateiändung cpp sondern z.b. mit tpl geschrieben).
cu André
-
asc schrieb:
alternativ die cpp includen...
Noch eine Alternative wäre das Schlüsselwort export, welches dem Compiler vorgaukelt, dass die Templatedefinitionen in der selben Datei stehen. Allerdings wird dieses Feature von den wenigsten Compilern unterstützt. (Von welchen, kann ich nicht sagen)
-
keyword ‘export’ not implemented, and will be ignored,
also nahm ich die 2. variante und habe #include "string_fnc.cpp" in string_fnc.h eingefügt als letzten #include (am anfang).doch nun bekomme ich folgende fehlermeldung:
error: #include nested too deeplydas ist wohl nun ein prob von meinem makefile (ist ein fertiges gewesen.)? oder ist das ein compiler-prob? weiss das jmd? nur das ich nicht am falschen ende suche - habe mich damit noch nicht befasst.
das makefile:
TARGET := ./abc CXXFLAGS := -g -W -Wall -Wno-long-long -pedantic -std=c++98 CXX := g++ LIBS := EXT := cpp BUILDDIR := build override BUILDDIR := $(strip $(BUILDDIR)) SOURCES := $(wildcard *.$(EXT)) OBJECTS := $(patsubst %.$(EXT), $(BUILDDIR)/%.o, $(SOURCES)) DEPS := $(patsubst %.$(EXT), $(BUILDDIR)/%.dep, $(SOURCES)) .PHONY: all all: $(TARGET) $(TARGET): $(OBJECTS) $(DEPS) $(CXX) $(CXXFLAGS) -o $(TARGET) $(OBJECTS) $(LIBS) ifneq ($(MAKECMDGOALS), clean) -include $(DEPS) endif $(OBJECTS): $(BUILDDIR)/%.o: %.$(EXT) $(BUILDDIR)/%.dep $(BUILDDIR)/.tag $(CXX) $(CXXFLAGS) -c $< -o $@ $(DEPS): $(BUILDDIR)/%.dep: %.$(EXT) $(BUILDDIR)/.tag $(CXX) $(CXXFLAGS) -MM $< -MT $@ -MT $(<:.$(EXT)=.o) -o $@ %.tag: mkdir -p $(dir $(@)) touch $@ .PHONY: clean clean: rm -rf $(BUILDDIR)
-
thx @ all
deklariere und definiere die template funktion nun im header so ist es ok.
alles andere will irgendwie nicht.btw: wenn ich meinen post noch mal in der vorschau lese, log ich mich rel. schnell aus. kann ich das abschalten? finde keine einstellung dafür.
-
ähm google mal nach includeguards... Dein compiler liest folgendes:
#include string_fnc.h //ok machen wir #include string_fnc.cpp // na jut #include string_fnc.h // schon wieder? was solls #include string_fnc.cpp // ähm... #include string_fnc.h // ich glaube da stimmt was nicht...du merkst es nach 6 Zeilen - Compiler sind geduldig und tun was du ihnen sagst, bis sie irgendwann (so nach 1000 includes oder mehr) nicht mehr können und das Handtuch werfen.
Die Lösung bei templates ist wie folgt:
- um den Header (wie um jeden anderen auch) einen include-guard machen
- die .cpp in der .h am ENDE includieren (sonst würde der compiler zu recht meckern, dass du die funktionen definierst bevor du sie deklariert hast)
- in der .cpp (die vielleicht wirklich besser .tpl oder so heißen sollte ums klar zu machen) KEIN include der .h
-
solito schrieb:
keyword ‘export’ not implemented, and will be ignored,
Welchen Compiler hast du denn?
-
mikey schrieb:
asc schrieb:
alternativ die cpp includen...
Noch eine Alternative wäre das Schlüsselwort export, welches dem Compiler vorgaukelt, dass die Templatedefinitionen in der selben Datei stehen. Allerdings wird dieses Feature von den wenigsten Compilern unterstützt. (Von welchen, kann ich nicht sagen)
Diese Alternative habe ich nicht vorgeschlagen weil es meiner Kenntnis nach nur einen einzigen Compiler gibt der dieses Feature unterstützt: Comeau C++
(Was auch der Compiler mit der höchsten Standardkonformität sein soll)cu André
-
Okay, du hast Recht mit dem Comeau C++ Compiler:
http://de.wikipedia.org/wiki/Comeau_C%2B%2BDann waren das also die jenigen, die stolze 5 Jahre an diesem export-Feature programmiert haben.
-
mikey schrieb:
solito schrieb:
keyword ‘export’ not implemented, and will be ignored,
Welchen Compiler hast du denn?
gcc version 4.1.2
-
wenn jmd noch etwas geduld hätte wäre das super
(habe die trim_str() funktion mal rausgenommen)string_fnc.h
#include <sstream> #include <stdexcept> #include <string> #ifndef string_fnc_h_INCLUDED #define string_fnc_h_INCLUDED template<typename T> T to_numeric (const std::string& data); #include "string_fnc.cpp" #endifstring_fnc.cpp
#ifndef string_fnc_h_INCLUDED #define string_fnc_h_INCLUDED #include "string_fnc.h" #endif using namespace std; template<typename T> T to_numeric(const string& data) { istringstream str(data); T val; str >> val; if (!str) { throw invalid_argument("string to numeric failed - invalid argument"); } return val; }es functioniert - endlich... ist doch korrekt so?

und würdet ihr die datei auch wenn sie nicht nur templates enthält nach .tpl umbenennen oder gar
eine neue .tpl datei erstellen und diese dann noch in die cpp-datei einbinden.
wird das dann nicht zu unübersichtlich falls sich doch mal jmd. anderes den code anschaut?
-
solito schrieb:
wenn jmd noch etwas geduld hätte wäre das super
(habe die trim_str() funktion mal rausgenommen)Ich persönlich setze Templates zwar nur in Headern ein, aber das ist Geschmackssache. Grundlegend würde ich dir aber folgendes raten:
1. using namespace gehört niemals in Dateinen die direkt includiert werden (Sprich: Header auf der einen Seite und Template-Sourcefiles).
2. nur das includieren was wirklich an der Stelle nötig ist.
3. Includeguard müssen einmalig gewählt werdenMeine Variante deines Codes (der an sich ungeprüft ist):
string_fnc.h
#include <sstream> #include <stdexcept> #include <string> #ifndef string_fnc_header #define string_fnc_header template<typename T> T to_numeric(const std::string& data) { std::istringstream str(data); T val; str >> val; if(!str) throw std::invalid_argument("string to numeric failed - invalid argument"); return val; } #endif // string_fnc_headersolito schrieb:
und würdet ihr die datei auch wenn sie nicht nur templates enthält nach .tpl umbenennen oder gar eine neue .tpl datei erstellen und diese dann noch in die cpp-datei einbinden.
Grundsätlich solltest du lieber Templates vom Rest trennen. Besonders wenn du Templates in Header und Source trennst.
Warum?
Man sollte nicht Gefahr laufen das man Teile inkludiert, die eigentlich nicht inkludiert gehören.
Zumal es auch besser lesbar ist.Natürlich spricht nichts dagegen mehrere Templates in einer Datei zu haben (sofern diese nicht zu groß wird).
cu André
-
-
Wenn du Deklaration und Implementierung trennen willst kannst du auch ein ".inl" File machen, und das im ".hpp" File inkludieren.
Dabei ist es durchaus üblich dass das ".inl" File das dazugehörige ".hpp" File NICHT inkludiert, und auch keine include Guards enthält. Wenn man sich daran hält das ".inl" File immer nur im dazugehörigen ".hpp" File (ganz unten) zu inkludieren macht das auch keine Probleme.
Ansonsten pack wie vorgeschlagen wurde die Implementierung auch einfach mit ins ".hpp" File - ist sehr üblich, und auch einfacher.
-
mikey schrieb:
Okay, du hast Recht mit dem Comeau C++ Compiler:
http://de.wikipedia.org/wiki/Comeau_C%2B%2BDann waren das also die jenigen, die stolze 5 Jahre an diesem export-Feature programmiert haben.
IMO gibt's die export Implementierung von der EDG und steht auch im neuen Borland Compiler zur Verfügung
-
Die derzeit aktuelle version des BCB2007 unterstützt export nicht.