2017-09-07 10 views
7

Następujące kompilowane przy użyciu VS2015, ale kończy się niepowodzeniem w VS2017 z poniższymi błędami. Czy kod wykonał coś niestandardowego, które zostało naprawione w VS2017, czy powinien je skompilować VS2017?Dlaczego ten szablon funkcji enable_if nie może być wyspecjalizowany w VS2017?

#include "stdafx.h" 
#include <type_traits> 

template <typename E> 
constexpr auto ToUnderlying(E e) 
{ 
    return static_cast<std::underlying_type_t<E>>(e); 
} 

template<typename T> 
bool constexpr IsFlags(T) { return false; } 

template<typename E> 
std::enable_if_t<IsFlags(E{}), std::underlying_type_t<E>> operator | (E lhs, E rhs) 
{ 
    return ToUnderlying(lhs) | ToUnderlying(rhs); 
} 

enum class PlantFlags { green = 1, edible = 2, aromatic = 4, frostTolerant = 8, thirsty = 16, growsInSand = 32 }; 

bool constexpr IsFlags(PlantFlags) { return true; } 

int main() 
{ 
    auto ored = PlantFlags::green | PlantFlags::frostTolerant; 

    return 0; 
} 

Błędy są:

c:\main.cpp(24): error C2893: Failed to specialize function template 'enable_if<false,_Ty>::type 
operator |(E,E)' 
     with 
     [ 
      _Ty=underlying_type<_Ty>::type 
     ] 
c:\main.cpp(24): note: With the following template arguments: 
c:\main.cpp(24): note: 'E=PlantFlags' 
c:\main.cpp(24): error C2676: binary '|': 'PlantFlags' does not define this operator or a conversion to a type acceptable to the predefined operator 
+0

@ Jarod42 ah, tak, dzięki będę pozbyć się tego. –

+1

To [kompiluje na clangu i gcc] (https://godbolt.org/g/oKUxtQ) – Justin

+1

Visual C++ prawdopodobnie błędnie zakłada, że ​​'IsFlags (E {})' jest zawsze fałszywe. Edycja: [wygląda na to, że nie jest taki, jak się spodziewałem] (https://godbolt.org/g/sHS1Dh) – Justin

Odpowiedz

5

Jest to zdecydowanie błąd w Visual Studio. To compiles on GCC and Clang. Wydaje się być związany z funkcjami constexpr ocenianymi jako parametry szablonu. Jako tymczasowe rozwiązanie, można dokonać zmiennej szablonu:

template <typename T> 
bool constexpr is_flags_v = IsFlags(T{}); 

template<typename E> 
std::enable_if_t<is_flags_v<E>, std::underlying_type_t<E>> operator | (E lhs, E rhs) 
{ 
    return ToUnderlying(lhs) | ToUnderlying(rhs); 
} 

On Godbolt

+0

Wydaje się działać, dziękuję. –

+0

@ScottLangham Byłoby dobrze złożyć raport o błędzie z Visual Studio – Justin

+0

Czy zgłosiliście ten błąd? –

4

Może to być błąd w Visual Studio. Możliwym obejściem problemu może być użycie specjalizacji szablonu zamiast przeciążania:

template <typename T> 
struct is_flags { constexpr static bool value = false; }; 

template <> 
struct is_flags<PlantFlags> { constexpr static bool value = true; }; 

template<typename E> std::enable_if_t<is_flags<E>::value, std::underlying_type_t<E >> operator | (E lhs, E rhs) 
{ 
    return ToUnderlying(lhs) | ToUnderlying(rhs); 
} 
+0

na której wersji Visual Studio był ten kod uruchomić? –

+1

Dzięki za sugestię. Intencją oryginalnego kodu jest umożliwienie wybranym wyliczeniom pracy z operatorami bitowymi, a nie innymi. Nie jestem pewien, czy to obejście może to osiągnąć. –

+1

Użyłem Microsoft Optimized C++ Compiler w wersji 19.11.25507.1, zawartej w VS 2017.3. – Jodocus