J'apprends la métaprogrammation de modèles. Lorsque j'essaie de tester un membre statique en utilisant le code suivant, le second SFINAE renvoie toujours une valeur erronée :
#include <cstdio>
#include <type_traits>
// ts_a
struct ts_a
{
static int a;
};
// ts_b
struct ts_b
{
static int b;
};
// has_a
template<typename T, typename = std::void_t<>>
struct has_a : std::false_type {};
template<typename T>
struct has_a<T, std::void_t<decltype( T::a )>> : std::true_type {};
// has_b
template<typename T, typename = std::void_t<>>
struct has_b : std::false_type {};
template<typename T>
struct has_b<T, std::void_t<decltype( T::b )>> : std::true_type {};
int main()
{
printf( "%s\n", has_a<ts_a>::value ? "true" : "false" );
printf( "%s\n", has_b<ts_a>::value ? "true" : "false" );
printf( "%s\n", has_a<ts_b>::value ? "true" : "false" );
printf( "%s\n", has_b<ts_b>::value ? "true" : "false" );
return 0;
}
J'utilise le compilateur optimisant Microsoft (R) C/C++ version 19.15.26732.1 pour x64.
true
true
false
false
Cependant, lors de la compilation avec GCC, il retourne la valeur attendue.
true
false
false
true
Quand on définit has_b avant has_a ( CTRL-XV has_b avant has_a ), MSVC retourne
false
false
true
true
Alors, est-ce un problème de compilateur ?
L'alternative suivante fonctionne sur les deux compilateurs, mais elle renvoie également true pour les membres non-statiques. Existe-t-il un moyen de détecter les membres statiques réels ?
template <class T>
struct has_a_2
{
template<typename U>
static std::true_type check( decltype( U::a )* );
template<typename U>
static std::false_type check(...);
public:
static constexpr const bool value = decltype( check<T>( 0 ) )::value;
};