Constexpr falls alternativ

Lesezeit: 5 Minuten

Benutzer-Avatar
Aart Stuurmann

Ich möchte verwenden constexpr if zur Kompilierzeit zu verzweigen, scheint aber vom neuesten MSVC-Compiler nicht unterstützt zu werden. Gibt es eine Alternative zu Folgendem?:

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

Kurzum: Kann ich simulieren constexpr if wenn es vom Compiler nicht unterstützt wird?

  • Es ist eine C++17-Funktion

    – max66

    24. April 2017 um 11:58 Uhr

  • Ja, ich weiß, das Problem ist, dass das neueste MSVC C ++ 17 nicht vollständig unterstützt.

    – Aart Stuurmann

    24. April 2017 um 12:01 Uhr

  • Könnte interessant sein: statische_wenn-mit-c11c14 simulieren

    – Jarod42

    24. April 2017 um 12:26 Uhr


Benutzer-Avatar
Sternenlicht

Eine der Möglichkeiten vor C++17 ist die Verwendung partieller Template-Spezialisierungen, wie hier:

template <typename 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();
}

Wenn Sie mehr als 2 Spezialisierungen benötigen, können Sie Aufzählungen oder ganzzahlige Werte verwenden und Spezialisierungen für alle erforderlichen Aufzählungen vornehmen.

Eine andere Möglichkeit ist die Verwendung von 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>();
}

Sie können es auf die altmodische und bewährte Weise des Tag-Versands tun:

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>{});
}

Benutzer-Avatar
Justin

Wenn Sie C++ 14 und Boost verwenden, sollten Sie die Verwendung von Hanna. Implementiert mit Hana sieht das etwa so aus:

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

Für den speziellen Fall, SFINAE zu erkennen und nur in diesem Fall etwas auszuführen, könnte das so einfach sein wie:

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

Es gibt in der Tat mehrere Alternativen (die schon lange im Einsatz waren if constexpr begann zu existieren).

Einer ist der Tag-Versand:

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>{});
}

Ein weiterer sind Eigenschaften:

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>();
}

Benutzer-Avatar
max66

if constexpr ist eine C++17-Funktion; vor C++17, ab C++11, können Sie SFINAE mit verwenden std::enable_if

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>(); }

— BEARBEITEN —

Wenn Sie nur einen C++98-Compiler verwenden können, implementieren Sie Typeigenschaften, die wie funktionieren std::enable_if ist wirklich einfach; siehe folgendes Beispiel

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

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

und die Funktionen werden

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>(); }

  • SFINAE benötigt kein C++11, es war immer in C++ vorhanden.

    – Angew ist nicht mehr stolz auf SO

    24. April 2017 um 12:02 Uhr

  • @Angew – dein Recht: ist std::enable_if das ist in C++11 verfügbar, nicht in SFINAE; Danke; Antwort geändert

    – max66

    24. April 2017 um 12:04 Uhr


  • Es gibt immer boost::enable_if wenn C++11 keine Option ist.

    – Angew ist nicht mehr stolz auf SO

    24. April 2017 um 12:08 Uhr

  • @Angew – ja, aber ich ziehe es vor, eine Antwort zu geben, die nicht standardmäßige APIs vermeidet; andernfalls implementieren Sie a std::enable_if wie Typmerkmale ist es so kurz und einfach … danke für den Vorschlag; Antwort geändert

    – max66

    24. April 2017 um 12:32 Uhr


Benutzer-Avatar
García Sylvain

Daran bin ich vor kurzem hängengeblieben … Also habe ich ein Tiny erstellt if_constexpr Bibliothek für die Rückportierung von c++17-Code nach c++14.

#include <if_constexpr.hpp>

template<typename T>
constexpr void MyFunc()
{
    using namespace ic;
    if_<MeetsConditions<T>::value>([] {
        FunctionA<T>();
    }, else_([] {
        FunctionB<T>();
    }));
}

  • SFINAE benötigt kein C++11, es war immer in C++ vorhanden.

    – Angew ist nicht mehr stolz auf SO

    24. April 2017 um 12:02 Uhr

  • @Angew – dein Recht: ist std::enable_if das ist in C++11 verfügbar, nicht in SFINAE; Danke; Antwort geändert

    – max66

    24. April 2017 um 12:04 Uhr


  • Es gibt immer boost::enable_if wenn C++11 keine Option ist.

    – Angew ist nicht mehr stolz auf SO

    24. April 2017 um 12:08 Uhr

  • @Angew – ja, aber ich ziehe es vor, eine Antwort zu geben, die nicht standardmäßige APIs vermeidet; andernfalls implementieren Sie a std::enable_if wie Typmerkmale ist es so kurz und einfach … danke für den Vorschlag; Antwort geändert

    – max66

    24. April 2017 um 12:32 Uhr


1015770cookie-checkConstexpr falls alternativ

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy