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.