J'ai besoin d'un moyen facile d'affirmer à l'intérieur d'un modèle qu'un paramètre de modèle implémente une méthode (ou l'une de ses classes parentes). J'ai lu la bibliothèque de chèques Concept, mais il est difficile de trouver un exemple simple pour faire des contrôles simples comme celui-ci.méthode compile time assertion; toujours ne fonctionne pas
J'ai essayé de suivre d'autres postes (comme this one et this other one), que j'ai modifié pour que je puisse le rendre générique pour de nombreux types de méthode (dans mon exemple Foo (methodName) et has_foo (nom Checker) sera, une fois fonctionne correctement, être enveloppé comme arguments macro de sorte qu'il peut être utilisé pour toute méthode)
le code que j'ai pour le moment est celui-ci:
template <typename TypeToBeChecked, typename Sign>
class has_foo {
static_assert(false , "inside root declaration of " "has_foo");
public:
static const bool result = false;
};
template <typename TypeToBeChecked , typename R>
class has_foo < TypeToBeChecked , R(void) >
{
static_assert(false , "inside specialization of " "has_foo" " for R(void)");
class yes { char m;};
class no { yes m[2];};
struct BaseMixin { R Foo(){} };
struct Base : public TypeToBeChecked, public BaseMixin {};
template <typename T, T t> class Helper{};
template <typename U> static no deduce(U*, Helper<R (BaseMixin::*)(), &U::Foo>* = 0);
static yes deduce(...);
public:
static const bool result = sizeof(yes) == sizeof(deduce((Base*)(0)));
};
template <typename TypeToBeChecked , typename R , typename ARG1>
class has_foo< TypeToBeChecked , R(ARG1) >
{
static_assert(false , "inside specialization of " "has_foo" " for R(ARG1)");
class yes { char m;};
class no { yes m[2];};
struct BaseMixin { R Foo(ARG1){} };
struct Base : public TypeToBeChecked, public BaseMixin {};
template <typename T, T t> class Helper{};
template <typename U>
static no deduce(U*, Helper<R (BaseMixin::*)(ARG1), &U::Foo>* = 0);
static yes deduce(...);
public:
static const bool result = sizeof(yes) == sizeof(deduce((Base*)(0)));
};
template <typename TypeToBeChecked , typename R , typename ARG1 , typename ARG2>
class has_foo< TypeToBeChecked , R(ARG1, ARG2) >
{
static_assert(false , "inside specialization of " "has_foo" " for R(ARG1 , ARG2)");
class yes { char m;};
class no { yes m[2];};
struct BaseMixin { R Foo(ARG1,ARG2){} };
struct Base : public TypeToBeChecked, public BaseMixin {};
template <typename T, T t>
class Helper{};
template <typename U>
static no deduce(U*, Helper<R (BaseMixin::*)(ARG1,ARG2), &U::Foo>* = 0);
static yes deduce(...);
public:
static const bool result = sizeof(yes) == sizeof(deduce((Base*)(0)));
};
template< typename Type >
struct Connector
{
static_assert(has_foo< Type , int(int, double) >::result , "Type has no Foo method");
void Operate() {
Type t;
t.Foo(3);
}
};
struct Bla1 { int Foo(double f) { return (int)f; } };
struct Bla2 { int Foo(int g, double h) { return g+(int)h;} };
int main()
{
//Connector<Bla1> a;
Connector<Bla2> b;
};
Quand je compile ce code exemple (g ++ 4.4. 3 ubuntu avec l'option -std = C++ 0x pour que le static_assert soit reconnu) je reçois ceci:
$ g++ test.cpp -std=c++0x -o test
test.cpp:72: error: static assertion failed: "inside root declaration of has_foo"
test.cpp:79: error: static assertion failed: "inside specialization of has_foo for R(void)"
test.cpp:93: error: static assertion failed: "inside specialization of has_foo for R(ARG1)"
test.cpp:108: error: static assertion failed: "inside specialization of has_foo for R(ARG1 , ARG2)"
attente juste là, (notez que connecteur < Bla1> a est commenté) ma première question est:
1) Ai-je raison de supposer que si l'affirmation est en cours d'évaluation, le modèle contenant est étant instancié?
EDIT: répondu par GMan: static_assert est évalué pendant l'analyse, et non lorsque le modèle est instancié. Remplacer false par sizeof (TypeToBeChecked) == 0 le lie à l'heure de compilation
2) Ai-je raison de supposer que puisque l'assertion statique à l'intérieur de la classe du modèle Connecteur instancie has_foo avec la signature int (int, double), alors les spécialisations sans paramètre et sans paramètre NE DOIVENT PAS être instanciées? Qu'est-ce qui ne va pas avec mes hypothèses?
EDIT: cette hypothèse est juste, mais maintenant que je fixe selon 1) réponse, le processus d'instanciation est maintenant comporte comme prévu
3) si je décommenter le connecteur < Bla1> une ligne, j'attendre échouer (puisque Bla1 n'a qu'un Foo avec une seule signature de paramètre, mais ce n'est pas le cas.) Toute idée de ce qui pourrait être erroné, en tenant particulièrement compte du premier article lié
La statique aFFIRME toujours déclencher. 'false' est faux, indépendamment de tout ce que vous pourriez éventuellement faire, donc le compilateur doit le déclencher ici et là. Si vous voulez qu'il soit dépendant, faites quelque chose comme 'sizeof (TypeToBeChecked) == 0', qui est à la fois faux et dépendant. – GManNickG
intéressant, donc static_assert est évalué au moment de l'analyse, plutôt que de compiler – lurscher