Ist es möglich, eine Vorlage zu schreiben, die das Verhalten ändert, je nachdem, ob eine bestimmte Elementfunktion für eine Klasse definiert ist?
Hier ist ein einfaches Beispiel dafür, was ich schreiben möchte:
template<class T>
std::string optionalToString(T* obj)
{
if (FUNCTION_EXISTS(T->toString))
return obj->toString();
else
return "toString not defined";
}
Wenn also class T
hat toString()
definiert, dann verwendet er es; sonst nicht. Der magische Teil, den ich nicht zu tun weiß, ist der Teil "FUNCTION_EXISTS".
Antworten:
Ja, mit SFINAE können Sie überprüfen, ob eine bestimmte Klasse eine bestimmte Methode bietet. Hier ist der Arbeitscode:
Ich habe es gerade mit Linux und gcc 4.1 / 4.3 getestet. Ich weiß nicht, ob es auf andere Plattformen portierbar ist, auf denen andere Compiler ausgeführt werden.
quelle
typeof
durch,decltype
wenn C ++ 0x verwendet wird , z. B. über -std = c ++ 0x.Diese Frage ist alt, aber mit C ++ 11 haben wir eine neue Möglichkeit, die Existenz einer Funktion (oder die Existenz eines Nicht-Typ-Mitglieds) zu überprüfen, wobei wir uns wieder auf SFINAE verlassen:
Nun zu einigen Erklärungen. Als erstes verwende ich den Ausdruck SFINAE , um die
serialize(_imp)
Funktionen von der Überladungsauflösung auszuschließen , wenn der erste Ausdruck darindecltype
nicht gültig ist (auch bekannt als die Funktion existiert nicht).Mit
void()
wird der Rückgabetyp aller dieser Funktionen festgelegtvoid
.Das
0
Argument wird verwendet, um dieos << obj
Überladung zu bevorzugen, wenn beide verfügbar sind (Literal0
ist vom Typint
und als solches stimmt die erste Überladung besser überein).Jetzt möchten Sie wahrscheinlich, dass ein Merkmal überprüft, ob eine Funktion vorhanden ist. Zum Glück ist es einfach, das zu schreiben. Beachten Sie jedoch, dass Sie für jeden gewünschten Funktionsnamen selbst ein Merkmal schreiben müssen .
Live Beispiel.
Und weiter zu den Erklärungen. Erstens
sfinae_true
handelt es sich um einen Hilfstyp, der im Grunde dem Schreiben entsprichtdecltype(void(std::declval<T>().stream(a0)), std::true_type{})
. Der Vorteil ist einfach, dass es kürzer ist.Als nächstes
struct has_stream : decltype(...)
erbt das entwederstd::true_type
oderstd::false_type
am Ende, je nachdem, ob dasdecltype
Eincheckentest_stream
fehlschlägt oder nicht.Zuletzt erhalten
std::declval
Sie einen "Wert" für jeden Typ, den Sie übergeben, ohne dass Sie wissen müssen, wie Sie ihn erstellen können. Beachten Sie, dass dies innerhalb eines unevaluierten Kontext nur dann möglich ist, wie zum Beispieldecltype
,sizeof
und andere.Beachten Sie, dass dies
decltype
nicht unbedingt erforderlich ist, dasizeof
(und alle nicht bewerteten Kontexte) diese Verbesserung erhalten haben. Es ist nur so, dassdecltype
bereits ein Typ geliefert wird und als solcher nur sauberer ist. Hier ist einesizeof
Version einer der Überladungen:Die Parameter
int
undlong
sind aus demselben Grund immer noch vorhanden. Der Array-Zeiger wird verwendet, um einen Kontext bereitzustellen, in demsizeof
verwendet werden kann.quelle
decltype
oversizeof
besteht auch darin, dass ein temporäres Element nicht durch speziell gestaltete Regeln für Funktionsaufrufe eingeführt wird (Sie müssen also keine Zugriffsrechte auf den Destruktor des Rückgabetyps haben und verursachen keine implizite Instanziierung, wenn der Rückgabetyp ist eine Instanziierung einer Klassenvorlage).static_assert(has_stream<X, char>() == true, "fail X");
kompiliert und nicht bestätigt wird, da char in int konvertierbar ist. Wenn dieses Verhalten also nicht erwünscht ist und alle Argumenttypen übereinstimmen sollen, weiß ich nicht, wie dies erreicht werden kann?In C ++ kann SFINAE dafür verwendet werden (beachten Sie, dass dies mit C ++ 11-Funktionen einfacher ist, da es erweitertes SFINAE für nahezu beliebige Ausdrücke unterstützt - das Folgende wurde für die Verwendung mit gängigen C ++ 03-Compilern entwickelt):
Die obige Vorlage und das Makro versuchen, eine Vorlage zu instanziieren, indem sie einen Elementfunktionszeigertyp und den tatsächlichen Elementfunktionszeiger erhält. Wenn die Typen nicht passen, wird die Vorlage von SFINAE ignoriert. Verwendung wie folgt:
Beachten Sie jedoch, dass Sie diese
toString
Funktion nicht einfach in diesem if-Zweig aufrufen können . Da der Compiler in beiden Zweigen die Gültigkeit überprüft, schlägt dies in Fällen fehl, in denen die Funktion nicht vorhanden ist. Eine Möglichkeit besteht darin, SFINAE erneut zu verwenden (enable_if kann auch über Boost abgerufen werden):Viel Spaß damit. Der Vorteil davon ist, dass es auch für überladene Elementfunktionen und auch für konstante Elementfunktionen funktioniert (denken Sie daran, dann
std::string(T::*)() const
als Elementfunktionszeigertyp zu verwenden!).quelle
type_check
wird, um sicherzustellen, dass die Signaturen genau übereinstimmen. Gibt es eine Möglichkeit, es so zu gestalten, dass es mit jeder Methode übereinstimmt, die so aufgerufen werden kann, wie eine Methode mit SignaturSign
aufgerufen werden kann? (ZB wennSign
=std::string(T::*)()
, lassen Siestd::string T::toString(int default = 42, ...)
übereinstimmen.)T
darf kein primitiver Typ sein, da die Zeiger-auf-Methode-von-T-Deklaration nicht SFINAE unterliegt und für Nicht-Klasse-T-Fehler fehlerhaft ist. IMO Die einfachste Lösung besteht darin, sie mitis_class
Prüfung von zu kombinieren Boost.toString
Funktion ausführen, wenn es sich um eine Vorlagenfunktion handelt?C ++ 20 -
requires
AusdrückeMit C ++ 20 kommen Konzepte und verschiedene Tools wie
requires
Ausdrücke, die eine integrierte Methode sind, um die Existenz einer Funktion zu überprüfen. Mit ihnen können Sie IhreoptionalToString
Funktion wie folgt umschreiben :Pre-C ++ 20 - Erkennungs-Toolkit
N4502 schlägt ein Erkennungs-Toolkit für die Aufnahme in die C ++ 17-Standardbibliothek vor, das es schließlich in die Grundlagen der Bibliothek TS v2 geschafft hat. Es wird höchstwahrscheinlich nie in den Standard aufgenommen, da es seitdem durch
requires
Ausdrücke subsumiert wurde , aber es löst das Problem dennoch auf eine etwas elegante Art und Weise. Das Toolkit enthält einige Metafunktionen, mitstd::is_detected
denen Metafunktionen zur Typ- oder Funktionserkennung einfach darüber geschrieben werden können. So können Sie es verwenden:Beachten Sie, dass das obige Beispiel nicht getestet wurde. Das Erkennungs-Toolkit ist noch nicht in Standardbibliotheken verfügbar. Der Vorschlag enthält jedoch eine vollständige Implementierung, die Sie bei Bedarf problemlos kopieren können. Es spielt sich gut mit der C ++ 17-Funktion
if constexpr
:C ++ 14 - Boost.Hana
Boost.Hana baut anscheinend auf diesem speziellen Beispiel auf und bietet in seiner Dokumentation eine Lösung für C ++ 14, daher werde ich es direkt zitieren:
Boost.TTI
Ein weiteres etwas idiomatisches Toolkit zur Durchführung einer solchen Prüfung - wenn auch weniger elegant - ist Boost.TTI , das in Boost 1.54.0 eingeführt wurde. Für Ihr Beispiel müssten Sie das Makro verwenden
BOOST_TTI_HAS_MEMBER_FUNCTION
. So können Sie es verwenden:Dann können Sie mit die
bool
SFINAE-Prüfung erstellen.Erläuterung
Das Makro
BOOST_TTI_HAS_MEMBER_FUNCTION
generiert die Metafunktion,has_member_function_toString
die den markierten Typ als ersten Vorlagenparameter verwendet. Der zweite Vorlagenparameter entspricht dem Rückgabetyp der Elementfunktion, und die folgenden Parameter entsprechen den Typen der Funktionsparameter. Das Mitgliedvalue
enthält,true
ob die KlasseT
eine Mitgliedsfunktion hatstd::string toString()
.Alternativ
has_member_function_toString
kann ein Elementfunktionszeiger als Vorlagenparameter verwendet werden. Daher ist es möglich,has_member_function_toString<T, std::string>::value
durch zu ersetzenhas_member_function_toString<std::string T::* ()>::value
.quelle
Obwohl diese Frage zwei Jahre alt ist, werde ich es wagen, meine Antwort hinzuzufügen. Hoffentlich klärt es die vorherige, unbestreitbar ausgezeichnete Lösung. Ich nahm die sehr hilfreichen Antworten von Nicola Bonelli und Johannes Schaub und führte sie zu einer Lösung zusammen, die meiner Meinung nach besser lesbar und klar ist und keine
typeof
Erweiterung erfordert :Ich habe es mit gcc 4.1.2 überprüft. Der Kredit geht hauptsächlich an Nicola Bonelli und Johannes Schaub, also stimmen Sie ab, wenn meine Antwort Ihnen hilft :)
quelle
toString
. Wenn Sie eine generische Bibliothek schreiben, die mit einer beliebigen Klasse da draußen arbeiten möchte (denken Sie an etwas wie Boost), kann es inakzeptabel sein, dass der Benutzer zusätzliche Spezialisierungen für einige obskure Vorlagen definiert. Manchmal ist es vorzuziehen, einen sehr komplizierten Code zu schreiben, um die öffentliche Schnittstelle so einfach wie möglich zu halten.Eine einfache Lösung für C ++ 11:
Update, 3 Jahre später: (und das ist ungetestet). Um die Existenz zu testen, denke ich, dass dies funktionieren wird:
quelle
template<typename>
die variable Überlastung machen: Es wurde nicht für die Lösung in Betracht gezogen.Dafür gibt es Typmerkmale. Leider müssen sie manuell definiert werden. Stellen Sie sich in Ihrem Fall Folgendes vor:
quelle
&T::x
oder implizit durch Binden an eine Referenz).type traits
für die bedingte Kompilierung in C ++ 11Nun, diese Frage hat bereits eine lange Liste von Antworten, aber ich möchte den Kommentar von Morwenn hervorheben: Es gibt einen Vorschlag für C ++ 17, der es wirklich viel einfacher macht. Siehe N4502 für Details, aber als eigenständiges Beispiel betrachten Sie Folgendes.
Dieser Teil ist der konstante Teil, setzen Sie ihn in eine Kopfzeile.
Dann gibt es den variablen Teil, in dem Sie angeben, wonach Sie suchen (einen Typ, einen Elementtyp, eine Funktion, eine Elementfunktion usw.). Im Fall des OP:
Das folgende Beispiel aus N4502 zeigt eine ausführlichere Sonde:
Im Vergleich zu den anderen oben beschriebenen Implementierungen ist diese ziemlich einfach: Ein reduzierter Satz von Werkzeugen (
void_t
unddetect
) reicht aus, ohne dass haarige Makros erforderlich sind. Außerdem wurde berichtet (siehe N4502 ), dass es messbar effizienter ist (Kompilierungszeit und Compiler-Speicherverbrauch) als frühere Ansätze.Hier ist ein Live-Beispiel . Es funktioniert gut mit Clang, aber leider folgten GCC-Versionen vor 5.1 einer anderen Interpretation des C ++ 11-Standards, was dazu führte
void_t
, dass es nicht wie erwartet funktionierte. Yakk hat die Problemumgehung bereits bereitgestellt: Verwenden Sie die folgende Definition vonvoid_t
( void_t in der Parameterliste funktioniert, jedoch nicht als Rückgabetyp ):quelle
Dies ist eine C ++ 11-Lösung für das allgemeine Problem, wenn "Wenn ich X machen würde, würde es kompilieren?"
Merkmal
has_to_string
,has_to_string<T>::value
dastrue
genau dannT
ist, wenn es eine Methode.toString
gibt, die in diesem Zusammenhang mit 0 Argumenten aufgerufen werden kann.Als nächstes würde ich Tag Dispatching verwenden:
Dies ist tendenziell wartbarer als komplexe SFINAE-Ausdrücke.
Sie können diese Merkmale mit einem Makro schreiben, wenn Sie es häufig tun, aber sie sind relativ einfach (jeweils ein paar Zeilen), sodass es sich möglicherweise nicht lohnt:
Mit den obigen Anweisungen wird ein Makro erstellt
MAKE_CODE_TRAIT
. Sie übergeben ihm den Namen des gewünschten Merkmals und einen Code, mit dem der Typ getestet werden kannT
. Somit:erstellt die oben genannte Merkmalsklasse.
Abgesehen davon ist die obige Technik Teil dessen, was MS als "Ausdruck SFINAE" bezeichnet, und ihr 2013er Compiler schlägt ziemlich schwer fehl.
Beachten Sie, dass in C ++ 1y die folgende Syntax möglich ist:
Dies ist ein bedingter Inline-Kompilierungszweig, der viele C ++ - Funktionen missbraucht. Dies ist es wahrscheinlich nicht wert, da der Vorteil (dass Code inline ist) nicht die Kosten wert ist (so gut wie niemand versteht, wie es funktioniert), aber die Existenz dieser oben genannten Lösung kann von Interesse sein.
quelle
has_to_string
.Hier sind einige Verwendungsausschnitte: * Der Mut für all dies ist weiter unten
Suchen Sie nach Mitgliedern
x
in einer bestimmten Klasse. Könnte var, func, class, union oder enum sein:Auf Mitgliedsfunktion prüfen
void x()
:Auf Mitgliedsvariable prüfen
x
:Nach Mitgliedsklasse suchen
x
:Auf Mitgliedsgewerkschaft prüfen
x
:Auf Mitgliederliste prüfen
x
:Überprüfen Sie
x
unabhängig von der Signatur, ob ein Mitglied funktioniert :ODER
Details und Kern:
Makros (El Diablo!):
CREATE_MEMBER_CHECK:
CREATE_MEMBER_VAR_CHECK:
CREATE_MEMBER_FUNC_SIG_CHECK:
CREATE_MEMBER_CLASS_CHECK:
CREATE_MEMBER_UNION_CHECK:
CREATE_MEMBER_ENUM_CHECK:
CREATE_MEMBER_FUNC_CHECK:
CREATE_MEMBER_CHECKS:
quelle
sig_check<func_sig, &T::func_name>
zur freien Funktionsprüfung wechseln :sig_check<func_sig, &func_name>
Es kann nicht mit einer "nicht deklarierten Kennung" erstellt werden, in der der Name der zu prüfenden Funktion angegeben ist? weil ich erwarten würde, dass SFINAE es NICHT zu einem Fehler macht, tut es genau das für Mitglieder, warum nicht für kostenlose Funktionen?Ich habe eine Antwort darauf in einem anderen Thread geschrieben, der (im Gegensatz zu den obigen Lösungen) auch geerbte Mitgliedsfunktionen überprüft:
SFINAE, um nach geerbten Elementfunktionen zu suchen
Hier einige Beispiele aus dieser Lösung:
Beispiel 1:
Wir suchen nach einem Mitglied mit folgender Unterschrift:
T::const_iterator begin() const
Bitte beachten Sie, dass es sogar die Konstanz der Methode überprüft und auch mit primitiven Typen funktioniert. (Ich meine,
has_const_begin<int>::value
ist falsch und verursacht keinen Fehler bei der Kompilierung.)Beispiel 2
Jetzt suchen wir nach der Unterschrift:
void foo(MyClass&, unsigned)
Bitte beachten Sie, dass MyClass nicht standardmäßig konstruierbar sein oder ein spezielles Konzept erfüllen muss. Die Technik funktioniert auch mit Vorlagenelementen.
Ich warte gespannt auf Meinungen dazu.
quelle
Das war ein schönes kleines Puzzle - tolle Frage!
Hier ist eine Alternative zu Nicola Bonellis Lösung , die nicht auf dem nicht standardmäßigen
typeof
Operator basiert .Leider funktioniert es nicht unter GCC (MinGW) 3.4.5 oder Digital Mars 8.42n, aber unter allen Versionen von MSVC (einschließlich VC6) und unter Comeau C ++.
Der längere Kommentarblock enthält Details dazu, wie es funktioniert (oder funktionieren soll). Wie es heißt, bin ich mir nicht sicher, welches Verhalten den Standards entspricht - ich würde einen Kommentar dazu begrüßen.
Update - 7. November 2008:
Es sieht so aus, als ob dieser Code zwar syntaktisch korrekt ist, das Verhalten von MSVC und Comeau C ++ jedoch nicht dem Standard entspricht (danke an Leon Timmermans und litb, die mich in die richtige Richtung gelenkt haben ). Der C ++ 03-Standard sagt Folgendes aus:
Es sieht also so aus, als ob MSVC oder Comeau die
toString()
Mitgliedsfunktion zumT
Durchführen einer Namenssuche an der Aufrufstelle in Betracht ziehen,doToString()
wenn die Vorlage instanziiert wird. Dies ist falsch (obwohl es tatsächlich das Verhalten ist, nach dem ich in diesem Fall gesucht habe).Das Verhalten von GCC und Digital Mars scheint korrekt zu sein - in beiden Fällen ist die Nichtmitgliedsfunktion
toString()
an den Aufruf gebunden.Ratten - Ich dachte, ich hätte vielleicht eine clevere Lösung gefunden, stattdessen habe ich ein paar Compiler-Fehler entdeckt ...
quelle
Die hier von litb vorgestellte Standard-C ++ - Lösung funktioniert nicht wie erwartet, wenn die Methode zufällig in einer Basisklasse definiert ist.
Eine Lösung für diese Situation finden Sie unter:
Auf Russisch: http://www.rsdn.ru/forum/message/2759773.1.aspx
Englische Übersetzung von Roman.Perepelitsa: http://groups.google.com/group/comp.lang.c++.moderated/tree/browse_frm/thread/4f7c7a96f9afbe44/c95a7b4c645e449f?pli=1
Es ist wahnsinnig schlau. Ein Problem bei dieser Lösung besteht jedoch darin, dass Compilerfehler auftreten, wenn der zu testende Typ nicht als Basisklasse verwendet werden kann (z. B. primitive Typen).
In Visual Studio ist mir aufgefallen, dass bei der Arbeit mit Methoden ohne Argumente ein zusätzliches Paar redundanter () um die Argumente eingefügt werden muss, um () in der Größe des Ausdrucks abzuleiten.
quelle
struct g { void f(); private: void f(int); };
weil eine der Funktionen privat ist (dies liegt daran, dass der Code dies tutusing g::f;
, wodurch er fehlschlägt, wenn auf einef
nicht zugegriffen werden kann).MSVC verfügt über die Schlüsselwörter __if_exists und __if_not_exists ( Doc ). Zusammen mit dem Typ-SFINAE-Ansatz von Nicola konnte ich einen Check für GCC und MSVC erstellen, wie es das OP suchte.
Update: Quelle finden Sie hier
quelle
Ein Beispiel mit SFINAE und Template-Teilspezialisierung durch Schreiben einer
Has_foo
Konzeptprüfung:quelle
Ich habe die in https://stackoverflow.com/a/264088/2712152 bereitgestellte Lösung geändert , um sie etwas allgemeiner zu gestalten. Da es keine der neuen C ++ 11-Funktionen verwendet, können wir es auch mit alten Compilern verwenden und sollten auch mit msvc funktionieren. Die Compiler sollten es C99 jedoch ermöglichen, dies zu verwenden, da es verschiedene Makros verwendet.
Mit dem folgenden Makro können Sie überprüfen, ob eine bestimmte Klasse ein bestimmtes typedef hat oder nicht.
Das folgende Makro kann verwendet werden, um zu überprüfen, ob eine bestimmte Klasse eine bestimmte Elementfunktion mit einer bestimmten Anzahl von Argumenten hat oder nicht.
Wir können die obigen 2 Makros verwenden, um die Prüfungen für has_typedef und has_mem_func wie folgt durchzuführen:
quelle
HAS_MEM_FUNC( onNext, has_memberfn_onNext, void, Args... );
...template <typename V> struct Foo { void onNext(const V &); static_assert< has_memberfn_onNext<Foo<V>,const V &>::value, "API fail" ); };
Seltsamerweise schlug niemand den folgenden schönen Trick vor, den ich einmal auf dieser Seite gesehen habe:
Sie müssen sicherstellen, dass T eine Klasse ist. Es scheint, dass Mehrdeutigkeit bei der Suche nach foo ein Substitutionsfehler ist. Ich habe es auf gcc zum Laufen gebracht, bin mir aber nicht sicher, ob es Standard ist.
quelle
Die generische Vorlage, mit der überprüft werden kann, ob eine "Funktion" vom Typ unterstützt wird:
Die Vorlage, die prüft, ob es eine Methode
foo
gibt, die mit der Signatur kompatibel istdouble(const char*)
Beispiele
http://coliru.stacked-crooked.com/a/83c6a631ed42cea4
quelle
has_foo
in den Template-Aufruf von einzubindenis_supported
. Was ich möchte, ist etwas zu nennen wie :std::cout << is_supported<magic.foo(), struct1>::value << std::endl;
. Der Grund dafür ist, dass ichhas_foo
für jede unterschiedliche Funktionssignatur, die ich überprüfen möchte, eine definieren möchte, bevor ich nach der Funktion suchen kann.Wie wäre es mit dieser Lösung?
quelle
toString
es überlastet ist, da&U::toString
es nicht eindeutig ist.Hier gibt es viele Antworten, aber ich konnte keine Version finden, die eine echte Reihenfolge der Methodenauflösung ausführt , ohne eine der neueren C ++ - Funktionen zu verwenden (nur mit C ++ 98-Funktionen).
Hinweis: Diese Version wurde getestet und funktioniert mit vc ++ 2013, g ++ 5.2.0 und dem Onlline-Compiler.
Also habe ich eine Version entwickelt, die nur sizeof () verwendet:
Live-Demo (mit erweiterter Überprüfung des Rückgabetyps und vc ++ 2010-Problemumgehung): http://cpp.sh/5b2vs
Keine Quelle, da ich es mir selbst ausgedacht habe.
Beachten Sie beim Ausführen der Live-Demo auf dem g ++ - Compiler, dass Arraygrößen von 0 zulässig sind. Dies bedeutet, dass der verwendete static_assert keinen Compilerfehler auslöst, selbst wenn er fehlschlägt.
Eine häufig verwendete Problemumgehung besteht darin, das 'typedef' im Makro durch 'extern' zu ersetzen.
quelle
static_assert(false);
). Ich habe dies in Verbindung mit CRTP verwendet, um festzustellen, ob die abgeleitete Klasse eine bestimmte Funktion hat - was sich als nicht funktionierend herausstellt, aber Ihre Behauptungen wurden immer bestanden. Ich habe ein paar Haare verloren.Hier ist meine Version, die alle möglichen Überladungen von Elementfunktionen mit beliebiger Arität behandelt, einschließlich Vorlagenelementfunktionen, möglicherweise mit Standardargumenten. Es werden drei sich gegenseitig ausschließende Szenarien unterschieden, wenn ein Elementfunktionsaufruf einen Klassentyp mit bestimmten Argumenttypen ausführt: (1) gültig oder (2) mehrdeutig oder (3) nicht realisierbar. Anwendungsbeispiel:
Jetzt können Sie es so verwenden:
Hier ist der in C ++ 11 geschriebene Code. Sie können ihn jedoch problemlos (mit geringfügigen Änderungen) auf Nicht-C ++ 11 portieren, das über Erweiterungen verfügt (z. B. gcc). Sie können das Makro HAS_MEM durch Ihr eigenes ersetzen.
quelle
Sie können die gesamte Metaprogrammierung in C ++ 14 überspringen und diese einfach mit
fit::conditional
aus der Fit- Bibliothek schreiben :Sie können die Funktion auch direkt aus den Lambdas erstellen:
Wenn Sie jedoch einen Compiler verwenden, der keine generischen Lambdas unterstützt, müssen Sie separate Funktionsobjekte schreiben:
quelle
fit
einer anderen Bibliothek als dem Standard abhängig zu sein ?Mit C ++ 20 können Sie Folgendes schreiben:
quelle
Hier ist ein Beispiel für den Arbeitscode.
toStringFn<T>* = nullptr
aktiviert die Funktion, die ein zusätzlichesint
Argument akzeptiert, das Vorrang vor der Funktion hat, dielong
beim Aufruf mit verwendet wird0
.Sie können dasselbe Prinzip für die Funktionen verwenden, die zurückgegeben werden,
true
wenn die Funktion implementiert ist.quelle
Ich hatte ein ähnliches Problem:
Eine Vorlagenklasse, die möglicherweise von wenigen Basisklassen abgeleitet ist, von denen einige ein bestimmtes Mitglied haben und andere nicht.
Ich habe es ähnlich wie die Antwort "typeof" (Nicola Bonelli) gelöst, aber mit decltype, damit es auf MSVS kompiliert und korrekt ausgeführt wird:
quelle
Eine weitere Möglichkeit, dies in C ++ 17 zu tun (inspiriert von boost: hana).
Schreiben Sie es einmal und verwenden Sie es mehrmals. Es sind keine
has_something<T>
Klassen für Typmerkmale erforderlich .Beispiel
quelle
quelle