Static Template-Member explizit instantiieren



  • Hallo,

    nachdem ich mir das "Modern C++ Design" zu Gemüte geführt habe, bin ich ganz angetan von Policies.
    Aktuell scheitere ich aber seit längerem an folgender Situation: Ich habe eine Policy, die selber ein Template mit Template-Parameter T ist und darüber hinaus eine statische Variable vom Typ T hat. Eine Implementierungsklasse bekommt die Policy und den Typ T der Policy dann als Template-Parameter wie üblich:

    // main.cpp
    #include "Impl.cpp"
    #include "Policy.h"
    
    template class Impl<Policy, int>;
    template<> int Policy<int>::val = 5;
    
    int main()
    {
    	Impl<Policy, int>::bar();
    }
    
    // Impl.h
    #ifndef IMPL_H_
    #define IMPL_H_
    
    template<template <class> class P, class T>
    class Impl
    {
    public:
    	Impl();
    	~Impl();
    
    	static void bar();
    };
    #endif /*IMPL_H_*/
    
    // Impl.cpp
    #include "Impl.h"
    #include <iostream>
    
    template<template <class> class P, class T>
    Impl<P, T>::Impl()
    {
    }
    
    template<template <class> class P, class T>
    Impl<P, T>::~Impl()
    {
    }
    
    template<template <class> class P, class T>
    void Impl<P, T>::bar()
    {
    	P<T>::foo();
    }
    
    // Policy.h
    #ifndef POLICY_H_
    #define POLICY_H_
    
    #include <iostream>
    
    template<typename T>
    class Policy
    {
    public:
    	Policy() {};
    	~Policy() {};	
    
    	static void foo() {
    		std::cout << "Policy foo(): " << val << std::endl;
    	};
    
    	static T val;
    };
    #endif /*POLICY_H_*/
    

    So wie es jetzt da steht klappt das wunderbar. Und ja, ich will statische Methoden verwenden.

    Was mir nicht gefällt ist, dass ich in Zeile 6 den static Member der Policy explizit instantiieren muß, da ansonsten der Linker meckert (gcc 4.2.4)...
    Was ich gerne hätte wäre eine explizite Instanziierung der Policy im Bereich der Impl/Policy Klassen abhängig von deren Template Parametern (also insbesondere T).
    => Als "Benutzer" der Impl-Klasse möchte ich eigentlich nur max. diese explizit instantiieren, ohne etwas über die Interna der Policy wissen zu müssen.

    Die Krönung wäre dann noch wenn für T nicht nur ein "normaler" Typ wie int, sondern eine allgemeine Klasse verwendet werden könnte. Nach meiner bisherigen Recherche scheint das aber Probleme zu machen (anscheinend klappt es nur mit einem Zeiger auf die Klasse...)?

    Hat jemand einen Tipp für mich?

    Danke,
    steginger


  • Administrator

    Einfach die Sache in den Policy Header packen, dann geht das.

    // Policy.h
    #ifndef POLICY_H_
    #define POLICY_H_
    
    #include <iostream>
    
    template<typename T>
    class Policy
    {
    public:
        Policy() {};
        ~Policy() {};    
    
        static void foo() {
            std::cout << "Policy foo(): " << val << std::endl;
        };
    
        static T val;
    };
    
    // Kannst du auch hier hin schreiben! Dann ist es allerdings uninitialisiert.
    template<typename T>
    T Policy<T>::val;
    
    // Spezialisierungen sind auch möglich:
    template<>
    int Policy<int>::val = 6;
    
    #endif /*POLICY_H_*/
    

    Und man kann dann auch eine normale Klasse verwenden:

    int main()
    {
        // Zum Beispiel mit einem std::string.
        Impl<Policy, std::string>::bar();
    
        return 0;
    }
    

    Oder verstehe ich dich falsch?

    Grüssli


  • Mod

    steginger schrieb:

    Was mir nicht gefällt ist, dass ich in Zeile 6 den static Member der Policy explizit instantiieren muß, da ansonsten der Linker meckert (gcc 4.2.4)...

    Das ist keine Definition oder Instantiierung eines statischen Templatemembers sondern die Definition eines statischen Klassenmembers (die Klasse ist zufällig eine Templateklasse). Diese müsstest du auch ohne Templates durchführen, nicht zuletzt, um einen Initialisierer festzulegen.

    template<typename T>
    class Policy
    {
    public:
        Policy() {};
        ~Policy() {};   
    
        static void foo() {
            std::cout << "Policy foo(): " << val << std::endl;
        };
    
        static T val;
    };
    template<typename T>
    T Policy<T>::val;
    

    ist evtl. das, was du willst.

    Was ich gerne hätte wäre eine explizite Instanziierung der Policy im Bereich der Impl/Policy Klassen abhängig von deren Template Parametern (also insbesondere T).
    => Als "Benutzer" der Impl-Klasse möchte ich eigentlich nur max. diese explizit instantiieren, ohne etwas über die Interna der Policy wissen zu müssen.

    Die Krönung wäre dann noch wenn für T nicht nur ein "normaler" Typ wie int, sondern eine allgemeine Klasse verwendet werden könnte. Nach meiner bisherigen Recherche scheint das aber Probleme zu machen (anscheinend klappt es nur mit einem Zeiger auf die Klasse...)?

    Hat jemand einen Tipp für mich?

    ich verstehe dein Problem nicht, demonstriere es doch einmal mit Code.



  • Hallo,

    danke euch beiden. Mit

    // Kannst du auch hier hin schreiben! Dann ist es allerdings uninitialisiert.
    template<typename T>
    T Policy<T>::val;
    

    klappts, auch wenn T eine andere echte Klasse ist.

    Irgendwann wird man anscheinend betriebsblind...
    Die Lösung habe ich im eigentlichen Code schon x-mal die letzten Tage rauf und runter probiert, aber immer "Undefined references" beim statischen Member bekommen.
    Beim Nachbauen in das kleine Beispiel hab' ich es anscheinend dann doch nicht mehr ausprobiert und prompt liegt der Fehler wohl in irgendeiner Kleinigkeit irgendwo drumherum. Sind noch ein paar andere Templates dabei, da kann sich noch genügend verstecken... 🙂

    Danke nochmal,
    steginger


Log in to reply