TL; DR Ich mag eine Template-Funktion Process(T value)
schreiben, die unterschiedlich für unterschiedliche Werte verhält sich in Abhängigkeit von der Existenz einer nicht-Elementfunktion CreateProcessor<T>()
. Was kann ich dafür tun?SFINAE zum Erfassen Existenz Drittschablonenfunktion
Ich habe ein Problem mit SFINAE. Angenommen, wir müssen die Funktion CreateProcessor
unterstützen, die eine Implementierung der Schnittstelle IProcessor<T>
für einen Typ vom Typ T
zurückgibt.
In C++ können wir nicht mehrere Überladungen einer Funktion erzeugen, die sich nur im Rückgabetyp unterscheiden, also müssen wir die Funktion CreateProcessor
auch als Template-Funktion parametrieren, die durch T
parametrisiert wird.
Nehmen wir nun an, dass wir eine Template-Funktion Process<T>(T value)
schreiben wollen, die auf Existenz CreateProcessor<T>()
je funktioniert anders, nämlich sollte es value
unter Verwendung des Prozessors im Falle verarbeiten CreateProcessor<T>()
implementiert ist, sonst ist es zu Fehlern führen sollte.
ich versucht, den folgenden Code zu schreiben:
#include <cstdio>
#include <type_traits>
// A workaround for void_t as described here: http://en.cppreference.com/w/cpp/types/void_t.
template<typename... Ts> struct make_void { typedef void type;};
template<typename... Ts> using void_t = typename make_void<Ts...>::type;
// An interface for a processor that receives a value of specific type.
template<class T>
class IProcessor {
public:
virtual void process(T value) = 0;
};
// A processor for int.
class IntProcessor : public IProcessor<int> {
public:
virtual void process(int value) override {
printf("IntProcessor::process is called for value = %d\n", value);
}
};
// Template prototype.
template<class T>
IProcessor<T>* CreateProcessor();
// Template specialization for int.
template<>
IProcessor<int>* CreateProcessor() {
return new IntProcessor();
}
// Detector of CreateProcessor.
template<class, class=void>
struct CreateProcessorImplemented : std::false_type { };
template<class T>
struct CreateProcessorImplemented<T, void_t<decltype(CreateProcessor<T>())>> : std::true_type { };
// Specializations depending on existence of CreateProcessor.
template <typename T>
typename std::enable_if<CreateProcessorImplemented<T>::value, void>::type Process(T value) {
IProcessor<T>* processor = CreateProcessor<T>();
processor->process(value);
}
template <typename T>
typename std::enable_if<!CreateProcessorImplemented<T>::value, void>::type Process(T value) {
printf("Processor for requested typename is unavailable\n");
}
int main() {
Process(42);
Process("abc");
// static_assert(!CreateProcessorImplemented<char const*>::value, ":(");
/* This static_assert fails with an error:
* code.cpp:56:5: error: static assertion failed: :(
* static_assert(!CreateProcessorImplemented<char const*>::value, ":(");
*/
}
Obwohl dies in Verknüpfung Fehler führt:
/tmp/ccTQRc9N.o:code.cpp:function std::enable_if<CreateProcessorImplemented<char const*, void>::value, void>::type Process<char const*>(char const*): error: undefined reference to 'IProcessor<char const*>* CreateProcessor<char const*>()'
collect2: error: ld returned 1 exit status
Meine Idee ist, dass, wenn wir CreateProcessorImplemented<char const*>
lösen, decltype(CreateProcessor<const char*>())
nicht, weil nicht versagt ist Ein Template-Prototyp IProcessor<T> CreateProcessor()
und Compiler hält den Dekltyp gleich IProcessor<T>
, das ist irgendwie logisch, aber nicht das, was ich brauche.
'CreateProcessorImplemented' leitet sich immer von' std :: true_type', da eine Funktion müssen keine Implementierung haben für 'decltype' Ihnen zu sagen, den Rückgabetyp (siehe' std :: declval'). – Simple
@Simple, das macht Sinn. Ich glaube, es gibt keine Möglichkeit zu überprüfen, ob die Funktion eine Implementierung während der Kompilierzeit hat, da es ein Wissen vom Linker erfordert, richtig? –
Eine Alternative ist in der Antwort von @WojciechFrohberg. Sie verwenden eine "Struktur" mit einer statischen Elementfunktion anstelle einer Nichtmitgliedsfunktion. Sie können * erkennen, ob es keine statische Member-Funktion gibt, da die "Struktur" nicht spezialisiert ist. Es ist im Grunde eine Typeigenschaft. – Simple