Keine spezialisierten template-methoden in klassen template?



  • Hallo Leuts,

    Beim folgenden code tritt folgende Fehlermeldung auf:

    test2.cpp:80:12: Fehler: explizite Spezialisierung in Gültigkeitsbereich des Nicht-Namensbereiches »class compound_t<sub_words_t>«
    test2.cpp:81:34: Fehler: Template-ID »call_sub_words<0>« in Deklaration des ersten Templates
    

    Versteh ich das jetzt richtig, dass Spezialisierungen von Templatemethoden in Templateklassen nicht erlaubt sind? Oder wo liegt der Fehler? Und wie umgehe ich das Problem am elegantesten?

    Danke,
    Martin

    template <typename ... sub_words_t>
    class compound_t
    {
    public:
      compound_t(sub_words_t ... sub_words)
        : sub_words(sub_words ...)
      {  }
    
      void operator()(vm_t &vm)
      {
        call_sub_words<sizeof...(sub_words_t)-1>(vm);
      }
    
    private:
      static vm_t *vm;
    
      template<std::size_t n>
      void call_sub_words(vm_t &vm)
      {
        std::get<n>(sub_words)(vm);
        call_sub_words<n-1>(vm);
      }
    
      template<>
      void call_sub_words<0>(vm_t &vm)
      {
        std::get<0>(sub_words)(vm);    
      }
    
      std::tuple<sub_words_t ...> sub_words;
    };
    


  • Sorry, das folgende hat im Beispiel nix verloren. Ist nur ein Überbleibsel einer Überlegung.

    static vm_t *vm;
    


  • Nein, du kannst member Funktionen nicht spezialisieren. Du kannst das aber umgehen, indem du in der template member Funktion ein template Objekt erstellst, das die eigentlich Aufgabe übernimmt.

    template<typename T>
    functor
    {
       void func( arg op )
       {
       }
    }
    
    template<>
    functor<int>
    {
       void func( arg op )
       {
       }
    }
    
    template<typename T>
    void someclass::func( arg op )
    {
       functor<T> f;
       f.func( op )
    }
    


  • Warum sollte ich den keine Membermethode spezialisieren dürfen? Folgendes funktioniert ohne Probleme:

    template< typename TT >
    class Test
    {
    public:
        template< int xx >
        void oper( int &C )
        {
    
        }
    
        template<>
        void oper<0>( int &C )
        {
    
        }
    };
    
    ...
    
    int var = 0;
    Test<int> obj;
    obj.oper<0>( var);
    

    Partielle Spezialisierung ist nicht erlaubt. Oder hat sich was im neuen Standard geändert?

    leftshift



  • Ist das standardkonform oder ein Feature deines Compilers?
    Habe auf die Schnelle nichts gefunden, aber ich musste das damals so lösen. Kann jetzt aber nicht ausschließen, dass das an der mangelnden Standardkonformität des Compilers (Borland) lag.


  • Mod

    Templatespezialisierungen sind grundsätzlich auf Namensraumebene zu deklarieren.

    DocShoes Delegation ist eine Variante. Möglich ist auch die Ersetzung der Rekursion durch eine Packexpansion. Damit erübrigt sich das Spezialisieren.
    z.B.

    #include <cstddef>
    #include <tuple>
    #include <iostream>
    
    template <typename T> struct identity
    {
        typedef T type;
    };
    
    template <std::size_t... i> struct index_list
        : identity<index_list<i...>> {};
    
    template <typename> struct append_index_list;
    template <std::size_t... i> struct append_index_list<index_list<i...>>
        : identity<index_list<0, (i+1)...>> {};
    
    template <std::size_t N> struct make_index_list
        : identity<typename append_index_list<typename make_index_list<N-1>::type>::type> {};
    template <> struct make_index_list<0>
        : identity<index_list<>> {};
    
    typedef int vm_t;
    
    template <int i> struct callable { void operator()(vm_t) const { std::cout << i << '\n'; } };
    
    template <typename ... sub_words_t>
    class compound_t
    {
    public:
      compound_t(sub_words_t ... sub_words)
        : sub_words(sub_words ...)
      {  }
    
      void operator()(vm_t &vm)
      {
        call_sub_words(vm,typename make_index_list<sizeof...(sub_words_t)>::type());
      }
    
    private:
      static vm_t *vm;
    
      template<std::size_t... i>
      void call_sub_words(vm_t &vm, index_list<i...>)
      {
        bool dummy[] = { ( std::get<i>(sub_words)(vm), false )... };
      }
    
      std::tuple<sub_words_t ...> sub_words;
    };
    
    template <typename ... sub_words_t>
    vm_t* compound_t<sub_words_t...>::vm = 0;
    
    int main()
    {
        vm_t a = 0;
        compound_t<callable<0>,callable<1>,callable<2>> b((callable<0>()),callable<1>(),callable<2>());
        b(a);
    }
    

    (es ist garantiert, dass die einzelnen std::get-Aufrufe in der richtigen Reihenfolge ausgeführt werden).



  • @camper, Da hast Du aber Nägel reingehauen! 👍


Anmelden zum Antworten