Linker: Templates + .cpp Datei = böse?



  • CStoll schrieb:

    PS: "extern" ist erstens nicht neu, zweitens von afaik nur einem Compiler wirklich umgesetzt worden und drittens auf bestem Weg, aus dem Sprachstandard gestrichen zu werden.

    Das war "export", was das Gegenteil von neu, nämlich deprecated ist.

    Extern template im C++0x-Standard sorgt dafür, dass das als extern deklarierte Template in der entsprechenden ÜE nicht instantiiert wird.

    @Topic: Wenn du die C-header nicht durch dein Projekt schleifen möchtest, musst du in den meisten ÜEs wohl auf die Definition der entsprechenden Funktionstemplates (das schließt Methoden von Klassentemplates mit ein) verzichten musst. Damit erübrigt sich das extern template für diese ÜEs, weil der Compiler dort sowieso nur die Deklarationen der entsprechenden Funktionen sieht. Allerdings musst du zu jeder Instantiierung der Funktionstemplates in irgendeiner ÜE auch die Definition mitliefern und dort instantiieren. Das wird ziemlich mühselig.

    Wenns dir um Sauberkeit des globalen namespace usw. geht, würde ich folgendes vorschlagen:
    Erstelle einen eigenen Header, sagen wir "cstdlib_forward.h", der passende Funktionen in einem eigenen namespace, sagen wir namespace cstdlib_fwd deklariert. Den bindest du in deinen Template-Header ein und rufst die Funktionen auf wie du sie brauchst. In cstdlib_forward.cpp werden die eigentlichen C-Header eingebunden und die Funktionen direkt an die entsprechenden C-Funktionen weitergeleitet. Ich lehne mich mal ganz weit aus dem Fenster und behaupte, dass ein aktueller Linker das erkennen und die extra-Funktion jeweils wegoptimieren sollte, so dass du einen sauberen globalen namespace und keinen Overhead haben solltest.



  • Mach halt so:

    namespace detail
    {
    int select_wrapper(...);
    int socket_wrapper(...);
    int send_wrapper(...);
    int recv_wrapper(...);
    // ...
    }
    // EDIT: std::iterator_traits<InputIterator>::value_type statt InputIterator::value_type
    template <typename InputIterator> 
     std::vector<typename std::iterator_traits<InputIterator>::value_type*> select(InputIterator begin, InputIterator end, int timeout, int microtimeout)
    {
        // implementieren mit Hilfe der "detail" Funktionen
    }
    

    Das ist so ziemlich *die* Standard-Variante wie man mit sowas umgeht. Also wenn man in den Header Files der eigenen LIB keine bösen fremden Header Files inkludieren will.



  • Kleine Anmerkung zum Code: statt InputIterator::value_type solltest du besser std::iterator_traits<InputIterator>::value_type verwenden.



  • ipsec schrieb:

    Kleine Anmerkung zum Code: statt InputIterator::value_type solltest du besser std::iterator_traits<InputIterator>::value_type verwenden.

    weshalb ?

    Meep Meep



  • Weil auch reine Pointer als Iteratoren verwendet werden könnten - und die haben keine Typedefs für Werttyp etc. (iterator_traits<> sammelt diese Hilfstypen je Iteratorklasse - die Standardversion verwendet It::value_type etc, aber eine Spezialisierung für Pointer überschreibt die Angaben)



  • Der Standard schreibt vor dass std::iterator_traits<InputIterator>::value_type funktionieren muss.
    Er schreibt nicht vor dass InputIterator::value_type funktionieren muss (und funktioniert auch nicht, z.B. für Zeiger wie CStoll schon geschrieben hat).

    Und man sollte sinnvollerweise das verwenden, was laut Standard funktionieren muss, und nicht das, was bloss zufälligerweise manchmal funktioniert.

    EDIT: sollte man nicht überhaupt std::iterator_traits<InputIterator>::pointer statt std::iterator_traits<InputIterator>::value_type* verwenden?



  • hustbaer schrieb:

    EDIT: sollte man nicht überhaupt std::iterator_traits<InputIterator>::pointer statt std::iterator_traits<InputIterator>::value_type* verwenden?

    Ja, sollte man 🙂



  • Gibts dafür einen Grund? In der Funktion selbst werfe ich ja sowieso Zeiger rein.



  • 314159265358979 schrieb:

    Gibts dafür einen Grund? In der Funktion selbst werfe ich ja sowieso Zeiger rein.

    Wenn du irgendwo in dem Funktionstemplates etwas machst, das nur mit rohen Zeigern funktioniert, dann kannst du auch value_type* lassen. Wenn (rein theoretisch) InputIterator::pointer auch ein anderer pointer-Typ sein kann und das dem Funktioniere des Templates keinen Abbruch tut, dann wäre es unnötig, durch Einschränkung des Typen auf value_type* die Verwendbarkeit einzuschränken.



  • std::iterator_traits<InputIterator>::pointer kommt doch ursprünglich von dem ganzen near/far Gedöns, nicht?
    Wobei man natürlich auch Smart-Pointer erlauben könnte.



  • Der Standard erlaubt gar keine proxies in den Containern (mal vom Beschiss in vector<bool> abgesehen). Daher muss eigentlich(!) pointer_type = value_type* sein, genauso wie reference_type = value_type* (wie gesagt, bis auf den beschiss in vector<bool>). Ausserdem gibt kein container irgendwo pointer_type zurück. von daher...



  • Hast du schonmal daran gedacht, daß auch Dinge außerhalb des C++ Standards existieren, die in der Lage sind, STL-taugliche Iteratoren zu liefern?

    (PS: Wenn schon, dann ist reference == value_type& ;))



  • 314159265358979 schrieb:

    pimpl kommt nicht in Frage, dafür ist eine Heap-Allokation erforderlich, und die ist zu teuer.

    Manchmal kommst du um Pimpl nicht herum, wenn du Abhängigkeiten verringern willst. Verwende in diesen Fällen einen speziellen Allokator.

    pumuckl schrieb:

    Das war "export", was das Gegenteil von neu, nämlich deprecated ist.

    "removed" triffts besser, export ist bald Geschichte 🙂



  • otze schrieb:

    Der Standard erlaubt gar keine proxies in den Containern (mal vom Beschiss in vector<bool> abgesehen). (...)

    Wer spricht denn von Proxies?

    Referenz != Zeiger
    std::iterator_traits<T>::reference != std::iterator_traits<T>::pointer

    IIRC gibt es keine Container-Funktionen die einen Zeiger zurückliefern würden. Von daher kann es auch keine "Proxy-Zeiger" geben.
    Trotzdem ermöglicht std::iterator_traits<T>::pointer es z.B. einen T __far* statt eines einfachen T* zu verwenden.


Anmelden zum Antworten