Generischer Typ für Container mit begin() und end()?



  • Moin,

    gibt es eine möglichkeit einen Templateparameter so einzuschränken, dass er nur Typen mit begin() und end() Memberfuntktion akzeptiert?

    template<typename T>
    void Klasse::pusht(T container)
    {
    	for(auto i: container)
    	{
    		push(i);
    	}
    }
    
    // Jetzt sollte folgendes funktionieren:
    std::vector<int> Vektor;
    std::list<int> Liste;
    Instanz.pusht(Vektor);
    
    // Folgendes jedoch nicht:
    int i = 1;
    Instanz.pusht(i);
    

    Prinzipiell funktioniert dies bereits wie es soll, aber die Fehlermeldungen beim Aufruf von pusht(int) werden der for-Schleife zugeordnet (offensichtlich, int hat ja keine begin-Methode). Schöner wäre es für mich, wenn ich einen generischen Typ für "Klassen mit begin() und end()" hätte. Gibt es soetwas?



  • Nicht wirklich, vielleicht bekommt man das mit ganz viel Meta-Gefrickel hin, aber letztlich kannst du es auch gleich so lassen. (Das ist übrigens der Grund warum alle auf Concepts warten, .. ;))



  • mit c++11 Unterstützung schmeist bei mir der compiler eine fehlermeldung, wenn der Type "T" kein begin() kennt:

    #include <vector>
    #include <iostream>
    using namespace std;
    
    template<typename T>
    void pusht(T container)
    {
        for(auto i: container)
        {
            std::cout<<i;
        }
    }
    
    int main()
    {
        vector<int> intvec;
        intvec.push_back(12);
    
        pusht(intvec);
    
        int t = 5;
    
        pusht(t);
    }
    

    Fehlermeldung:

    ../dffhfghfgh/test.cpp: In function 'void pusht(T) [with T = int]':
    ../dffhfghfgh/test.cpp:24:12: instantiated from here
    ../dffhfghfgh/test.cpp:8:5: error: no matching function for call to 'begin(int&)'
    ../dffhfghfgh/test.cpp:8:5: note: candidates are:
    /usr/lib/gcc/x86_64-pc-linux-gnu/4.6.1/include/g++-v4/bits/range_access.h:87:28: note: template<class _Tp, long unsigned int _Nm> _Tp* std::begin(_Tp (&)[_Nm])
    /usr/lib/gcc/x86_64-pc-linux-gnu/4.6.1/include/g++-v4/bits/range_access.h:58:63: note: template<class _Container> decltype (__cont.begin()) std::begin(const _Container&)
    /usr/lib/gcc/x86_64-pc-linux-gnu/4.6.1/include/g++-v4/bits/range_access.h:48:5: note: template<class _Container> decltype (__cont.begin()) std::begin(_Container&)
    /usr/lib/gcc/x86_64-pc-linux-gnu/4.6.1/include/g++-v4/initializer_list:86:38: note: template<class _Tp> constexpr const _Tp* std::begin(std::initializer_list<_Tp>)
    ../dffhfghfgh/test.cpp:8:5: error: no matching function for call to 'end(int&)'
    ../dffhfghfgh/test.cpp:8:5: note: candidates are:
    /usr/lib/gcc/x86_64-pc-linux-gnu/4.6.1/include/g++-v4/bits/range_access.h:97:26: note: template<class _Tp, long unsigned int _Nm> _Tp* std::end(_Tp (&)[_Nm])
    /usr/lib/gcc/x86_64-pc-linux-gnu/4.6.1/include/g++-v4/bits/range_access.h:78:59: note: template<class _Container> decltype (__cont.end()) std::end(const _Container&)
    /usr/lib/gcc/x86_64-pc-linux-gnu/4.6.1/include/g++-v4/bits/range_access.h:68:5: note: template<class _Container> decltype (__cont.end()) std::end(_Container&)
    /usr/lib/gcc/x86_64-pc-linux-gnu/4.6.1/include/g++-v4/initializer_list:96:36: note: template<class _Tp> constexpr const _Tp* std::end(std::initializer_list<_Tp>)
    ../dffhfghfgh/test.cpp:8:5: error: unable to deduce 'auto' from '<expression error>'



  • Man kann SFINAE ausnutzen (substitution failure is not an error). Z.B. so:

    template<class T, class...More>
    using First = T;
    
    namespace foo {
    
      using std::begin;
      using std::end;
    
      template<class C>
      auto dings(C const& c)
      -> First<void,decltype(begin(c),end(c))>
      {
        for (auto&& elem : c) {
          :::
        }
      }
    
    }
    

    Falls man über c so nicht iterieren kann, sind die Ausdrucke begin(c) und end(c) nicht gültig, was dazu führt, dass der Compiler den return-Typ nicht feststellen kann, was dazu führt, dass die die Deduktion von C fehlschlägt, was dazu führt, dass das Template ignoriert wird.


Anmelden zum Antworten