template-argumente einer basisklasse extrahieren



  • hi

    in meiner klassenhierarchie leiten ne menge klassen von derselben basisklasse ab. diese basisklasse ist eigentlich ein klassentemplate. da ich in der funktion f mit dem template-argument der basisklasse arbeiten möchte muss ich das irgendwie extrahieren

    template<int v>
    struct base { };
    
    template<typename T>
    void f(T const& x)
    {
    	//brauche hier x.base<>::v als compile-time-konstante (damit ich es an ein anderes template übergeben kann)
    }
    

    andererseits kann ich die signatur nicht in f(base<v> const&) ändern, da die abgeleiteten klassen gewisse methoden implementieren, die ich innerhalb von f auch noch brauche (ich brauche den übergebenen typen einfach...).

    kann ich das irgendwie bewerkstelligen, ohne dass v in abgeleiteten klassen zugänglich ist? (ja, die unmittelbar ableitenden klassen kennen v ohnehin, aber der "stammbaum" ist ziemlich gross und hat viele "generationen")


  • Mod

    hanstroll123 schrieb:

    andererseits kann ich die signatur nicht in f(base<v> const&) ändern

    aber als Hilfsfunktion taugt das.

    template<int v>
    struct base { };
    
    template <int v>
    std::integral_constant<int,v> base_helper(base<v>&&);
    
    template<typename T>
    void f(T const& x)
    {
        constexpr auto v = decltype(base_helper(x))::value;
    }
    


  • guter ansatz, wollte gerade fragen wie ich das in c++03 machen kann, habe es aber schon selbst geschafft (vorsicht, gebastel):

    #include <iostream>
    
    template<typename T>
    struct id { typedef T type; };
    
    template<int v>
    struct sz_type : public id<char(&)[v]> {};
    
    template<int v>
    struct base {};
    
    struct fun : base<42>
    {
    	void f() const { std::cout << "hello"; }
    };
    
    template<int v>
    typename sz_type<v>::type help(base<v> const&);
    
    template<typename T>
    void f(T const&x)
    {
    	x.f();
    	base<sizeof(help(x))>();
    }
    
    int main()
    {
    	f(fun());
    }
    

    jetzt nur noch für nicht-positive int's, hmm vll. zweierkomplement selbst anwenden.


  • Mod

    template <int v>
    std::integral_constant<int,v> base_helper(base<v>&&);
    
    template<typename T>
    void f(T const& x)
    {
        constexpr auto v = decltype(base_helper(x))::value;
    }
    

    😕 Ich glaube langsam du wirst Meschugge.

    Mit C++03 sieht das Ganze so aus:

    template <typename> struct extract;
    template <int v>
    struct extract<base<v>> {static int const value = v;};
    
    template<typename T>
    void f(T const& x)
    {
    	std::cout << extract<T>::value;
    }
    
    int main()
    {
    	f(base<4>());
    }
    

  • Mod

    Arcoth schrieb:

    😕 Ich glaube langsam du wirst Meschugge.

    Macht Spass, solltest du auch mal versuchen.

    Arcoth schrieb:

    Mit C++03 sieht das Ganze so aus:

    template <typename> struct extract;
    template <int v>
    struct extract<base<v>> {static int const value = v;};
    
    template<typename T>
    void f(T const& x)
    {
    	std::cout << extract<T>::value;
    }
    
    int main()
    {
    	f(base<4>());
    }
    

    langweilig


  • Mod

    Da du mein #1-Vorbild bist habe ich wohl keine Wahl als dir zu folgen.

    template <int v>
    char(&foo(base<v>))[v];
    
    template <typename T>
    void bar(T t)
    {
        std::cout << sizeof(foo(t));
    }
    

    Besser?



  • Der Umweg über integral_constant in C++11 scheint mir eigentlich ein bisschen von hinten durch die Brust ins Auge geschossen. Mit constexpr geht es direkter:

    #include <iostream>
    
    template<int v> struct base { };
    struct derived : base<4> { };
    
    // Wichtiger Teil hier
    template<int v>
    int constexpr f(base<v> const &) {
      return v;
    }
    // Wichtiger Teil zuende.
    
    int main() {
      derived d;
      std::cout << f(d) << '\n';
    
      base<f(d) * 2> b;
      std::cout << f(b) << '\n';
    }
    

  • Mod

    seldon schrieb:

    Der Umweg über integral_constant in C++11 scheint mir eigentlich ein bisschen von hinten durch die Brust ins Auge geschossen. Mit constexpr geht es direkter:

    Das macht allerdings nicht den Funktionsaufruf zu einem konstanten Ausdruck, wenn das Argument nicht konstant ist.

    include <iostream>
    
    template<int v> struct base { };
    struct derived : base<4> { };
    
    template<int v>
    int constexpr f(base<v> const &) {
      return v;
    }
    
    int main() {
        constexpr auto x = f(*new derived); //
    }
    


  • Arcoth schrieb:

    Mit C++03 sieht das Ganze so aus:

    template <typename> struct extract;
    template <int v>
    struct extract<base<v>> {static int const value = v;};
    
    template<typename T>
    void f(T const& x)
    {
    	std::cout << extract<T>::value;
    }
    
    int main()
    {
    	f(base<4>());
    }
    

    das ist nicht ganz das, was ich gesucht habe; T ist ein von base<v> abgeleiteter typ.

    hat jemand eine bessere c++03-lösung als die meine?


  • Mod

    Ups, tatsächlich, das war Quatsch.

    Dann nimm die zweite von mir gepostete, die funktioniert.


Anmelden zum Antworten