Constexpr如果替代

时间:2017-04-24 11:55:00

标签: c++ template-meta-programming c++17

我想在编译时使用constexpr if进行分支,但最新的MSVC编译器似乎并不支持它。是否有以下替代方案?:

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

简而言之:如果编译器不支持constexpr if,我可以模拟它吗?

6 个答案:

答案 0 :(得分:7)

前C ++中的一种方法是使用部分模板特化,如下所示:

template <template T, bool AorB>
struct dummy;

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

template <typename T, false>
struct dummy {
    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>();
}

答案 1 :(得分:7)

确实有几种替代方案(在if constexpr开始存在之前就已经使用过了。)

一个是标签发送:

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

另一个是特征:

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

答案 2 :(得分:5)

您可以使用老式的,久经考验的标签调度方式:

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

答案 3 :(得分:5)

如果您使用的是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>();
    });
}

答案 4 :(得分:4)

if constexpr是C ++ 17的一项功能;在C ++ 17之前,从C ++ 11开始,您可以将SFINAE与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>(); }

- 编辑 -

如果只能使用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>(); }

答案 5 :(得分:1)

我最近陷入困境... 因此,我创建了一个很小的if_constexpr library,用于将某些c ++ 17代码反向移植到c ++ 14。

#include <if_constexpr.hpp>

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