Constexpr 如果替代
Constexpr if alternative
我想在编译时使用constexpr if
分支,但最新的MSVC编译器似乎不支持。除了以下内容,还有其他选择吗?:
template<typename T>
void MyFunc()
{
if constexpr(MeetsConditions<T>::value)
{
FunctionA<T>();
}
else
{
FunctionB<T>();
}
}
简而言之:当编译器不支持时,我可以模拟constexpr if
吗?
您可以使用老式的、久经考验的标签分发方式:
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>{});
}
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>(); }
C++17 之前的一种方法是使用部分模板特化,如下所示:
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();
}
如果您需要超过 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>();
}
确实有几种选择(在 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>();
}
如果您使用的是 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>();
});
}
我最近卡在那个...
因此,我为 back-porting 一些 c++17 到 c++14 的代码创建了一个小的 if_constexpr
library。
#include <if_constexpr.hpp>
template<typename T>
constexpr void MyFunc()
{
using namespace ic;
if_<MeetsConditions<T>::value>([] {
FunctionA<T>();
}, else_([] {
FunctionB<T>();
}));
}
我想在编译时使用constexpr if
分支,但最新的MSVC编译器似乎不支持。除了以下内容,还有其他选择吗?:
template<typename T>
void MyFunc()
{
if constexpr(MeetsConditions<T>::value)
{
FunctionA<T>();
}
else
{
FunctionB<T>();
}
}
简而言之:当编译器不支持时,我可以模拟constexpr if
吗?
您可以使用老式的、久经考验的标签分发方式:
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>{});
}
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>(); }
C++17 之前的一种方法是使用部分模板特化,如下所示:
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();
}
如果您需要超过 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>();
}
确实有几种选择(在 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>();
}
如果您使用的是 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>();
});
}
我最近卡在那个...
因此,我为 back-porting 一些 c++17 到 c++14 的代码创建了一个小的 if_constexpr
library。
#include <if_constexpr.hpp>
template<typename T>
constexpr void MyFunc()
{
using namespace ic;
if_<MeetsConditions<T>::value>([] {
FunctionA<T>();
}, else_([] {
FunctionB<T>();
}));
}