Ich verwende die Funktion SFINAE stark in einem Projekt und bin mir nicht sicher, ob es Unterschiede zwischen den folgenden beiden Ansätzen gibt (außer Stil):
#include <cstdlib>
#include <type_traits>
#include <iostream>
template <class T, class = std::enable_if_t<std::is_same_v<T, int>>>
void foo()
{
std::cout << "method 1" << std::endl;
}
template <class T, std::enable_if_t<std::is_same_v<T, double>>* = 0>
void foo()
{
std::cout << "method 2" << std::endl;
}
int main()
{
foo<int>();
foo<double>();
std::cout << "Done...";
std::getchar();
return EXIT_SUCCESS;
}
Die Programmausgabe ist wie erwartet:
method 1
method 2
Done...
Ich habe gesehen, dass Methode 2 im Stapelüberlauf häufiger verwendet wird, aber ich bevorzuge Methode 1.
Gibt es Umstände, unter denen sich diese beiden Ansätze unterscheiden?
Antworten:
Vorschlag: Methode 2 bevorzugen.
Beide Methoden arbeiten mit einzelnen Funktionen. Das Problem tritt auf, wenn Sie mehr als eine Funktion mit derselben Signatur haben und nur eine Funktion des Satzes aktivieren möchten.
Angenommen, Sie aktivieren möchten
foo()
, Version 1, wennbar<T>()
(so tun , es ist eineconstexpr
Funktion) isttrue
, undfoo()
, Version 2, wennbar<T>()
istfalse
.Mit
Sie erhalten einen Kompilierungsfehler, weil Sie eine Mehrdeutigkeit haben: zwei
foo()
Funktionen mit derselben Signatur (ein Standardvorlagenparameter ändert die Signatur nicht).Aber die folgende Lösung
funktioniert, weil SFINAE die Signatur der Funktionen ändert.
Unabhängige Beobachtung: Es gibt auch eine dritte Methode: Aktivieren / Deaktivieren des Rückgabetyps (außer natürlich Klassen- / Strukturkonstruktoren)
Als Methode 2 ist Methode 3 mit der Auswahl alternativer Funktionen mit derselben Signatur kompatibel.
quelle
foo()
bleibt die Funktion verfügbar, wenn Sie sie mit einem expliziten zweiten Vorlagenparameter (demfoo<double, double>();
Aufruf) aufrufen. Und wenn verfügbar, besteht eine Mehrdeutigkeit mit der anderen Version. Bei Methode 2 aktiviert / deaktiviert SFINAE das zweite Argument, nicht den Standardparameter. Sie können es also nicht als Erklärung des Parameters bezeichnen, da ein Substitutionsfehler vorliegt, der keinen zweiten Parameter zulässt. Die Version ist also nicht verfügbar, also keine Mehrdeutigkeitauto foo() -> std::enable_if_t<...>
ist oft nützlich, um das Ausblenden der Funktionssignatur zu vermeiden und die Verwendung der Funktionsargumente zu ermöglichen.Neben der Antwort von max66 besteht ein weiterer Grund für die Bevorzugung von Methode 2 darin, dass Sie mit Methode 1 (versehentlich) einen expliziten Typparameter als zweites Vorlagenargument übergeben und den SFINAE-Mechanismus vollständig umgehen können. Dies kann als Tippfehler, Kopier- / Einfügefehler oder als Versehen in einem größeren Vorlagenmechanismus auftreten.
Live-Demo hier
quelle