!std::is_enum<SomeEnum>::value?

Given:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
class PlayState{
public:
    enum Value{
        STOPPED = 0,
        PLAYING,
        ENDING,
        PAUSED,
    };
    //...
};

template <typename T>
struct is_basic_type{
    static const bool value =
        std::is_integral<T>::value ||
        std::is_pointer<T>::value ||
        std::is_floating_point<T>::value ||
        std::is_enum<T>::value ||
        std::is_pod<T>::value && std::is_trivially_move_constructible<T>::value;
};

template <typename T>
typename std::enable_if<is_basic_type<T>::value, void>::type
move(T &dst, T &src){
    dst = std::move(src);
    src = {};
}

template <typename T>
typename std::enable_if<!is_basic_type<T>::value, void>::type
move(T &dst, T &src){
    dst = std::move(src);
}

void foo(){
    PlayState::Value x, y;
    move(x, y);
}
foo() calls the second overload of move(), rather than the first. It would appear that std::is_enum<PlayState::Value>::value is false, and I don't understand why.
closed account (z05DSL3A)
Not the result you describe...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
#include <iostream>
#include <type_traits>

class PlayState
{
  public:
    enum Value {
        STOPPED = 0,
        PLAYING,
        ENDING,
        PAUSED,
    };
    //...
};

template <typename T> 
struct is_basic_type
{
    static const bool value =
        std::is_integral<T>::value || std::is_pointer<T>::value ||
        std::is_floating_point<T>::value || std::is_enum<T>::value ||
        std::is_pod<T>::value && std::is_trivially_move_constructible<T>::value;
};

template <typename T>
typename std::enable_if<is_basic_type<T>::value, void>::type move(T &dst,
                                                                  T &src)
{
    std::cout << "Basic type Move()\n";
    dst = std::move(src);
    src = {};
}

template <typename T>
typename std::enable_if<!is_basic_type<T>::value, void>::type move(T &dst,
                                                                   T &src)
{
    std::cout << "Non-Basic type Move()\n";
    dst = std::move(src);
}

int main()
{ 
    std::cout << std::boolalpha;
    std::cout << std::is_enum<PlayState::Value>::value << '\n';
    std::cout << is_basic_type<PlayState::Value > ::value << '\n';
    std::cout << std::is_enum<int>::value << '\n';
    std::cout << is_basic_type<int>::value << '\n';

    PlayState::Value x {};
    PlayState::Value y {};
    move(x, y);
}
true
true
false
true
Basic type Move()

D:\Dev\source\repos\BlackFly\Debug\X-101.exe (process 6900) exited with code 0.
To automatically close the console when debugging stops, enable Tools->Options->Debugging->Automatically close the console when debugging stops.
Press any key to close this window . . .



unless of course this is some sort of April fools 'joke' to get people to waste there time with pointless japes...
Last edited on
unless of course this is some sort of April fools 'joke'
We don't do that here.

Hmm. It might be an MSVC bug, then.
Are you saying you have a different output for Grey Wolf's code? I have same output, VS 2019.
Well, I haven't tried it, but the debugger definitely steps into the wrong overload.
closed account (z05DSL3A)
I'm using MSVS 2019 (16.9.3).

When I put the code in there was a bit of moaning about the logical comparison:
Warning clang-diagnostic-logical-op-parentheses '&&' within '||'

and a warning from the first move() but I decided that just the uninitialized x, y that was being passed.
Warning clang-analyzer-core.uninitialized.Assign Assigned value is garbage or undefined

Edit: Warnings come from clang-tidy
Last edited on
When I compile GreyWolf's code above with VS2019 as C++20 (not using clang), I also need:

 
#define  _SILENCE_CXX20_IS_POD_DEPRECATION_WARNING 


as std::is_pod is depreciated in C++20.

I then get the same output.
In some circumstances MSVC appears to have trouble distinguishing templates which differ in signature. See this recent thread:
http://www.cplusplus.com/forum/general/276927/#msg1195251

If MSVC cannot distinguish the two templates, it may interpret your code as a violation of the one definition rule. This could explain why the wrong function is being called.

I'm convinced that you've written correct code in terms of the standard.

I'd love more information about this - if anyone knows better, please share.
Last edited on
@helios - I'd suggest reporting this to MS as a bug.
Topic archived. No new replies allowed.