Ich habe ein Problem mit einer C++ - Meta-Funktion, die ich nicht verstehe. Ich kompiliere auf Apples Build von clang 8.1.0 mit C++ 14. Arbeitscode, der das Problem veranschaulicht, ist unten.Probleme mit einer C++ - Metafunktion, um festzustellen, ob eine Funktion existiert
Ich habe eine Metafunktion von anderswo abgeschrieben und ich versuche es zu benutzen. Es soll Funktionen mit dem Namen 'bananify' erkennen, die einen Parameter des Typs haben, der an die Metafunktion übergeben wird. Sie nennen es als ...
BananifyDetector<int>::value
ist, sollte wahr zurück, wenn es eine deklarierte Funktion der Form sehen ...
bananify(int)
Das Problem ist, dass es funktioniert nur, wenn die Funktion gesucht wird für ist vor der Vorlage Definition BananifyFinder, im Gegensatz zu der Instanziierung davon deklariert. Also in meinem Beispiel-Code würde ich beide erwarten,
BananifyFinder<int>
BananifyFinder<std::string>
zu haben mit dem Code ist es mir gelungen unten, aber da, wo bananify (std :: string) definiert wurde, es funktioniert nicht.
Dies ist frustrierend, als ob ich Funktionsmelder in Header-Dateien, die ich Reihenfolge im Client-Code berücksichtigen muss, was eine tiefe Schmerzen und möglicherweise unmöglich ist, unter bestimmten Umständen richtig zu bringen.
Ich bin mir nicht sicher, was hier vor sich geht. Ist es ein C++ - Feature, ein Bug in Clang oder etwas Dummes, das ich gemacht habe?
Jede Hilfe wird geschätzt.
#include <iostream>
#include <type_traits>
////////////////////////////////////////////////////////////////////////////////
// A bananify function to be detected
// This is successfully found.
double bananify(int)
{
return 0.0;
}
/// A meta function that detects if a single argument function named 'bananify'
/// exists with takes an argument of the type passed to the metafunction.
///
/// Note, automatic casts will get in the way occasionally so if function
/// bananify(float) exists, a BananifyFinder<int>::value will return true.
template<class ARG1>
class BananifyFinder {
private :
template<typename ...> using VoidT_ = void;
template<typename A1, typename = void>
struct Test_ : std::false_type
{
typedef void returnType;
};
template<typename A1>
struct Test_<A1, VoidT_<decltype(bananify(std::declval<A1>()))>> : std::true_type
{
typedef decltype(bananify(std::declval<A1>())) returnType;
};
public :
typedef typename Test_<ARG1>::returnType returnType;
constexpr static bool value = Test_<ARG1>::value;
};
////////////////////////////////////////////////////////////////////////////////
// A bananify function to be detected that takes std::strings
// This fails to be found, but if we move it before the declaration of BananifyFinder it
// will be found;
std::string bananify(std::string)
{
return "s";
}
// dummy class with no bananify function to be found
class Nothing{};
// check the results of the metafunction 'T'
template<class T>
void CheckBanana(const std::string &str)
{
using DetectedType = BananifyFinder<T>;
std::cout << str << " detected is " << DetectedType::value << std::endl;
std::cout << str << " returns is " << typeid(typename DetectedType::returnType).name() << std::endl << std::endl;
}
////////////////////////////////////////////////////////////////////////////////
int main(int argc, char *argv[])
{
// this should print "BananifyFinder<int> 1 d"
CheckBanana<int>("BananifyFinder<int> ");
// this should print "BananifyFinder<std::string> 1 NSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEE"
// but it prints "BananifyFinder<std::string> 0 v"
// FAILS
CheckBanana<std::string>("BananifyFinder<std::string> ");
// this should print "BananifyFinder<Nothing> 0 v"
CheckBanana<Nothing>("BananifyFinder<Nothing> ");
}
korrekt zu sein, 'banify (std :: string)' muss detektiert werden _declared_ (und nicht _defined_), bevor die Vorlage 'BananifyFiner' werden . – YSC
Wären Sie in der Lage, einen 'std :: vector' zu verwenden, bevor Sie eine' #include ''? Genau das passiert hier. –
AndyG
AndyG, es ist eher so, als müsste ich MyClass deklarieren, bevor ich #include, bevor ich es benutzen kann. –
brunobignose