J'ai un problème avec une méta-fonction C++ que je ne comprends pas. Je compile sur la version d'Apple de clang 8.1.0, en utilisant C++ 14. Le code de travail qui illustre le problème est ci-dessous.Problèmes avec une métafonction C++ pour détecter si une fonction existe
J'ai créé une métafonction d'ailleurs et j'essaie de l'utiliser. Il est destiné à détecter les fonctions nommées 'bananify' qui ont un paramètre du type passé à la métafonction. Vous l'appelez comme ...
BananifyDetector<int>::value
est vrai devrait revenir si elle peut voir une fonction déclarée de la forme ...
bananify(int)
Le problème est qu'il ne fonctionne que si la fonction recherchée car est déclaré avant la définition de modèle de BananifyFinder, par opposition à l'instanciation de celui-ci. Donc, dans mon code exemple, je me serais attendu à la fois,
BananifyFinder<int>
BananifyFinder<std::string>
avoir réussi avec le code que j'ai ci-dessous, mais à cause de l'endroit où bananify (std :: string) a été définie, il échoue. C'est frustrant comme si je mettais des détecteurs de fonction dans des fichiers d'en-tête que je dois inclure dans le code client, ce qui est une douleur profonde et peut-être impossible à résoudre dans certaines circonstances.
Je ne suis pas sûr de ce qui se passe ici. Est-ce une fonctionnalité C++, un bug dans le clang ou quelque chose de stupide que j'ai fait?
Toute aide appréciée.
#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> ");
}
Pour être correct, 'banify (std :: string)' devez être _declared_ (et non _defined_) avant le modèle 'BananifyFiner' à détecter . – YSC
Souhaitez-vous être capable d'utiliser un 'std :: vector' avant d'avoir un' #include '? C'est ce qui se passe ici. –
AndyG
AndyG, c'est plus comme avoir à déclarer MyClass avant que je #include avant de pouvoir l'utiliser. –
brunobignose