Ich verwende SFINAE im Stil von this answer, um ein generisches Vektorobjekt unter Verwendung einer geeigneten Elementfunktion aufzurufen. Zum Beispiel ruft der folgende Code operator[](int) const
zuerst, und wenn das nicht dann operator()(int) const
existiert:C++ Warum scheitert SFINAE nur mit einem Klassenvorlagenparameter?
template<int I> struct rank : rank<I-1> { static_assert(I > 0, ""); };
template<> struct rank<0> {};
template<typename VectorType>
struct VectorWrapper
{
auto get(int i) const
{
return get(v, i, rank<5>());
}
template<typename V, typename = std::enable_if_t<has_bracket_operator<const V>::value> >
auto get(V const& v, int i, rank<2>) const
{
return v[i];
}
template<typename V, typename = std::enable_if_t<has_parenthesis_operator<const V>::value> >
auto get(V const& v, int i, rank<1>) const
{
return v(i);
}
VectorType v;
};
Mit den has_bracket_operator
und has_parenthesis_operator
Zügen eingerichtet wie in this thread vorgeschlagen, kompiliert das Ganze und seems to work.
Das Übergeben des Member-Vektors an die überlasteten Klassenvorlagen scheint jedoch von Anfang an unnötig zu sein, also habe ich versucht, dasselbe einzurichten, ohne es zu übergeben. Dazu ersetzen ich den Template-Parameter V
mit dem VectorType
Parameter zur Einrichtung der Klassenvorlage verwendet:
template<typename = std::enable_if_t<has_bracket_operator<VectorType>::value> >
auto get(int i, rank<2>) const
{
return v[i];
}
template<typename = std::enable_if_t<has_parenthesis_operator<VectorType>::value> >
auto get(int i, rank<1>) const
{
return v(i);
}
Nun aber schlägt die Kompilierung (in gcc 5.1.0) mit der folgenden Fehlermeldung:
/usr/local/include/c++/5.1.0/type_traits: In substitution of 'template<bool _Cond, class _Tp> using enable_if_t = typename std::enable_if::type [with bool _Cond = has_parenthesis_operator<std::vector<int> >::value; _Tp = void]':
main.cpp:46:10: required from 'struct VectorWrapper<std::vector<int> >'
main.cpp:59:38: required from here
/usr/local/include/c++/5.1.0/type_traits:2388:61: error: no type named 'type' in 'struct std::enable_if<false, void>'
using enable_if_t = typename enable_if<_Cond, _Tp>::type;
Fragen:
- Was ist der Grund für diesen Kompilierungsfehler?
- Gibt es eine andere Problemumgehung als die meines ersten Codeblocks? (Das heißt, einen, der den üblichen Kodierungsstil beibehält - wo man keine Mitglieder passieren muss).
Ich bin mir nicht sicher, ob der "unmittelbare Kontext" hier relevant ist (obwohl die Lösung vernünftig ist). Dies ist [CWG 1635] (http://wg21.link/cwg1635). –
@ T.C. Bedeutet das, dass es korrekt ist, nicht zu kompilieren, aber möglicherweise nicht, oder dass es kompilieren sollte und die Compiler einen Fehler haben? – Barry
Ich habe keine Ahnung, was CWG zu diesem Thema tun wird. Im Moment würde ich das wahrscheinlich unterspezifiziert nennen. –