web-dev-qa-db-ja.com

代替の場合はConstexpr

コンパイル時にconstexpr ifを使用して分岐したいのですが、最新のMSVCコンパイラではサポートされていないようです。次の代替手段はありますか?:

template<typename T>
void MyFunc()
{
    if constexpr(MeetsConditions<T>::value)
    {
        FunctionA<T>();
    }
    else
    {
        FunctionB<T>();
    }
}

つまり、コンパイラでサポートされていない場合にconstexpr ifをシミュレートできますか?

14
Aart Stuurman

C++ 17より前の方法の1つは、次のように部分的なテンプレートの特殊化を使用することです。

template <template T, bool AorB>
struct dummy;

template <typename T, true>
struct dummy {
    static void MyFunc() {  FunctionA<T>(); }
}

template <typename T, false>
struct dummy {
    static void MyFunc() {  FunctionB<T>(); }
}

template <typename T>
void Facade() {
    dummy<T, MeetsConditions<T>::value>::MyFunc();
}

2つ以上の特殊化が必要な場合は、列挙型または整数値を使用して、必要なすべての列挙型に対して特殊化を行うことができます。

別の方法は、std :: enable_if:を使用することです。

template <typename T>
std::enable_if<MeetsConditions<T>::value, void>::type
MyFunc() {
   FunctionA<T>();
}

template <typename T>
std::enable_if<!MeetsConditions<T>::value, void>::type
MyFunc() {
   FunctionB<T>();
}
7
Starl1ght

実際、いくつかの選択肢があります(if constexprが存在し始めるずっと前から使用されていました)。

1つはタグディスパッチです。

template <class T>
void Function(std::true_type)
{
  FunctionA<T>();
}

template <class T>
void Function(std::false_type)
{
  FunctionB<T>();
}

template <class T>
void MyFunc()
{
  Function<T>(std::integral_constant<bool, MeetsCondition<T>::value>{});
}

もう1つは特性です:

template <bool B>
struct FunctionTraits;

template <>
struct FunctionTraits<true>
{
  template <class T>
  static void Call() { FunctionA<T>(); }
};

template <>
struct FunctionTraits<false>
{
  template <class T>
  static void Call() { FunctionB<T>(); }
};

template <class T>
void MyFunc()
{
  FunctionTraits<MeetsCondition<T>::value>::Call<T>();
}
7
Angew

C++ 14とBoostを使用している場合は、 Hana の使用を検討してください。 Hanaを使用して実装すると、次のようになります。

template<typename T>
void MyFunc()
{
    hana::eval_if(MeetsConditions<T>::value,
        [](auto) { FunctionA<T>(); },
        [](auto _) { FunctionB<T>(_(exprThatWouldOtherwiseBeAnError)); }
    );
}

SFINAEを検出し、その場合にのみ何かを実行するという特定のケースでは、次のように簡単になります。

template<typename T>
void MyFunc()
{
    auto maybeDoFunctionA = hana::sfinae([]() -> decltype((void) FunctionA<T>()) {
        FunctionA<T>();
    });
}
6
Justin

昔ながらの、試行錯誤されたタグディスパッチ方法でそれを行うことができます。

template<typename T>
void MyFuncImpl(std::true_type) {
  FunctionA<T>();
}

template<typename T>
void MyFuncImpl(std::false_type) {
  FunctionB<T>();
}

template<typename T>
void MyFunc()
{
  MyFuncImpl<T>(std::integral_constant<bool, MeetsConditions<T>::value>{});
}
6
StoryTeller

if constexprはC++ 17の機能です。 C++ 17より前では、C++ 11以降、std::enable_ifでSFINAEを使用できます。

template<typename T>
typename std::enable_if<true == MeetsConditions<T>::value>::type MyFunc ()
{ FunctionA<T>(); }

template<typename T>
typename std::enable_if<false == MeetsConditions<T>::value>::type MyFunc ()
{ FunctionB<T>(); }

-編集-

C++ 98コンパイラのみを使用できる場合は、std::enable_ifのように機能する型特性を実装するのは非常に簡単です。次の例を参照してください

template <bool, typename = void>
struct enableIf
 { };

template <typename T>
struct enableIf<true, T>
 { typedef T type; };

そして機能は

template<typename T>
typename enableIf<true == MeetsConditions<T>::value>::type MyFunc ()
{ FunctionA<T>(); }

template<typename T>
typename enableIf<false == MeetsConditions<T>::value>::type MyFunc ()
{ FunctionB<T>(); }
4
max66