11

I've written the below code to try to detect if a type has a static member variable. Unfortunately, it's always returning that the variable does not exist.

Could someone tell me where I'm going wrong? I'm using g++ 4.7.1.

#include <iostream>
#include <utility>
#include <type_traits>

using namespace std;

template <class T>                                                  
class has_is_baz                                                          
{                                                                   
    template<class U, 
             typename std::enable_if<std::is_same<bool, decltype(U::is_baz)>::value>::type...>                    
        static std::true_type check(int);                           
    template <class>                                                
        static std::false_type check(...);                          
public:                                                             
    static constexpr bool value = decltype(check<T>(0))::value;     
};

struct foo { };

struct bar 
{ 
    static constexpr bool is_baz = true;
};

int main()
{
    cout << has_is_baz<foo>::value << '\n';
    cout << has_is_baz<bar>::value << '\n';
}
user1594173
  • 113
  • 1
  • 5

2 Answers2

11

The main problem was that:

std::is_same<bool, decltype(bar::is_baz)>::value == false

Then your SFINAE was failing always. I've re-written the has_is_baz trait and it now works:

#include <iostream>
#include <utility>
#include <type_traits>

using namespace std;

template <class T>                                                  
class has_is_baz                                                          
{       
    template<class U, class = typename std::enable_if<!std::is_member_pointer<decltype(&U::is_baz)>::value>::type>
        static std::true_type check(int);
    template <class>
        static std::false_type check(...);
public:
    static constexpr bool value = decltype(check<T>(0))::value;
};

struct foo { };

struct bar 
{ 
    static constexpr bool is_baz = true;
};

struct not_static {
    bool is_baz;
};

int main()
{
    cout << has_is_baz<foo>::value << '\n';
    cout << has_is_baz<bar>::value << '\n';
    cout << has_is_baz<not_static>::value << '\n';
}

Edit: I've fixed the type trait. As @litb indicated, it was detecting static members as well as non-static members.

David Hammen
  • 32,454
  • 9
  • 60
  • 108
mfontanini
  • 21,410
  • 4
  • 65
  • 73
  • This doesn't require `U::is_baz` to be static. A `struct A { bool is_baz; };` will just aswell work. – Johannes Schaub - litb Aug 14 '12 at 21:50
  • @JohannesSchaub-litb you're right. It looks like it works now. – mfontanini Aug 14 '12 at 22:19
  • The "Demo here" link is very broken. Instead of a demo of code compilation and execution, the link now takes one to a site that wants one to update FlashPlayer. I'm deleting the link. Someone can update this to a code test site that hasn't been usurped. – David Hammen May 13 '19 at 09:36
5

The issue in your code is that a constexpr object is implicitly const, which means that your test for same type should be:

std::is_same<const bool, decltype(U::is_baz)>::value

This is specified in the standard in §7.1.5 [dcl.constexpr]/9

A constexpr specifier used in an object declaration declares the object as const. [...]

David Rodríguez - dribeas
  • 204,818
  • 23
  • 294
  • 489
  • This answer was correct at the time it was written. Whether it is correct now depends on which version of the standard one is compiling against. Since C++14, a constexpr non-static member function is not const unless it is specifically qualified as such. – David Hammen May 13 '19 at 10:16