2017-09-07 11 views
7

以下はVS2015でコンパイルされますが、VS2017では以下のエラーで失敗します。コードがVS2017で修正された何か非標準的なことをしていたのですか、VS2017でコンパイルする必要がありましたか?なぜこのenable_if関数テンプレートは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; 
} 

エラーは以下のとおりです。

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

をああ、はい、おかげで私はそれを取り除くでしょう。 –

+1

これは[clangとgccでコンパイル](https://godbolt.org/g/oKUxtQ) – Justin

+1

Visual C++はおそらく間違って 'IsFlags(E {})'が常にfalseであると仮定しています。編集:[私が期待した方法ではないようだ](https://godbolt.org/g/sHS1Dh) – Justin

答えて

5

これは間違いなくVisual Studioのバグです。それはcompiles on GCC and Clangです。それはテンプレートのパラメータとして評価される関数と関連しているようです。一時的な回避策として、あなたはテンプレート変数を行うことができます。Jarod42 @

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

働いているようです、ありがとうございます。 –

+0

@ScottLangham Visual Studioでバグレポートを提出するとよいでしょう – Justin

+0

皆さんはバグを報告しましたか? –

4

これは、Visual Studioのバグかもしれません。回避策として、オーバーロードの代わりにテンプレートの特殊化を使用することが考えられます。

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

どのVisual Studioのバージョンでこのコードを実行しましたか? –

+1

提案していただきありがとうございます。元のコードの意図は、選択されたenumをビット演算子で動作させ、他のものでは動作させないことです。私はこの回避策がそれを達成できるかどうかはわかりません。 –

+1

VS2017.3に含まれているMicrosoft Optimized C++コンパイラのバージョン19.11.25507.1を使用しました。 – Jodocus

関連する問題