如果constexpr而不是标签调度
if constexpr instead of tag dispatch
我想使用if constexpr
而不是标签调度,但我不确定如何使用它。下面的示例代码。
template<typename T>
struct MyTag
{
static const int Supported = 0;
};
template<>
struct MyTag<std::uint64_t>
{
static const int Supported = 1;
};
template<>
struct MyTag<std::uint32_t>
{
static const int Supported = 1;
};
class MyTest
{
public:
template<typename T>
void do_something(T value)
{
// instead of doing this
bool supported = MyTag<T>::Supported;
// I want to do something like this
if constexpr (T == std::uint64_t)
supported = true;
}
};
一种方法是定义一个constexpr谓词,该谓词检查其参数类型,然后在该谓词的结果上进行constexpr switch。
我认为这种方式很好,因为它将功能逻辑与前提条件分开。
#include <iostream>
#include <cstddef>
#include <type_traits>
class MyTest
{
public:
template<typename T>
void do_something(T value)
{
// define our predicate
// lambdas are constexpr-if-possible in c++17
constexpr auto is_supported = [](auto&& x) {
if constexpr (std::is_same<std::decay_t<decltype(x)>, std::uint64_t>())
return true;
else
return false;
};
// use the result of the predicate
if constexpr (is_supported(value))
{
std::cout << "supportedn";
}
else
{
std::cout << "not supportedn";
}
}
};
int main()
{
auto t = MyTest();
t.do_something(int(0));
t.do_something(std::uint64_t(0));
t.do_something(double(0));
t.do_something(static_cast<unsigned long>(0)); // be careful with std::uint_xx aliases
}
示例结果:
not supported
supported
not supported
supported
表达这一点的另一种方法可能是:
class MyTest
{
public:
template<class T>
static constexpr bool something_possible(T&&)
{
return std::is_same<std::decay_t<T>, std::uint64_t>();
}
template<typename T>
void do_something(T value)
{
// switch behaviour on result of constexpr predicate
if constexpr (something_possible(value))
{
std::cout << "supportedn";
}
else
{
std::cout << "not supportedn";
}
}
};
通常对类型的运行时询问具有通用lambdas的功能编程(也有通用参数)。否则,简单的答案可能是:只需声明使用"必需"类型或使用类型特征等...回到通用lambdas的主题。
/// <summary>
/// c++ 17 generic lambdas have issues
/// with required types of auto arguments
/// in c++20 this will be fixed with new
/// lambda arguments template declaration syntax
/// until then ...
/// </summary>
namespace required_types
{
template<typename RQ>
inline auto is_required_type = [](const auto & v_ = 0) constexpr -> bool
{
using T = std::decay_t< decltype(v_) >;
return std::is_same<T, RQ>();
};
inline auto is_uint64 = [] ( const auto & v_ = 0 ) constexpr -> bool
{
return is_required_type<std::uint64_t>(v_);
};
} // required_types
namespace {
using namespace required_types;
inline auto tv = [](const char prompt[] = "", const auto & value) {
std::cout << prompt << "ntype:t" << typeid(decltype(value)).name() << "nvalue:t" << value;
};
inline auto make_double_value = [](auto value)
{
if constexpr (is_uint64(value)) {
tv("nnDoubling required type (std::uint_64):", value);
return value + value;
}
tv("nnWill try to double 'illegal' type", value);
return value + value;
};
}
一些用法
// call with 'legal' aka required type
std::uint64_t u42 = 42u;
auto double_value_2 = make_double_value(u42);
tv("nResult:", double_value_2);
// call with some 'illegal' types also works
auto double_value = make_double_value(42u);
tv("nResult:", double_value);
std::string one{"--ONE--"};
auto double_value_3 = make_double_value(one);
tv("nResult:", double_value_3 );
当然,如果一个人与我的简介不同意,仍然可以使用我的"必需_types":
template<typename T>
void some_proc ( const T && val_ ) {
using namespace required_types;
if constexpr ( is_required_type<std::uint64_t>(val_) ) {
do_something_with_uint64 (val_) ;
}
}
而不是上面,我宁愿使用std :: enable_if,沿此答案。
但是(如前所述)用于解决C 17中的几个通用lambdas问题,我会(大胆地)使用我的命名空间quired_types,并使用一些扩展名。
相关文章:
- 如何在c++中实现处理器调度模拟器
- C 和 C++ 中开关语句的案例标签的常量值,但显示不同的行为
- 如何正确指定 goto 语句的标签?
- 如何在 C++17 STL 并行算法中处理调度?
- 无法使用迭代器标记调度实例化模板
- 使用g++静态初始化带有命名标签的嵌套C++结构
- 在 c++11 中为 pthread 设置调度参数
- 通过水平滚动条更改标签
- 如何在 assert() 和 static_assert() 之间调度,如果在 constexpr 上下文中依赖?
- 从 QFontDatabase 设置 QFont 将所有标签设置为等宽字体?Qt C++
- 在C++中存储要输入的标签列表
- 如何在等效列表中查找最小的连接标签
- SFINAE和标签调度之间的差异
- C++ 如何按标签调度到不同的模板函数
- 标签调度以防止接口更改
- C++中的标签和枚举调度有什么区别
- 如果constexpr而不是标签调度
- 使用标签调度时如何反向模板参数
- 在标签调度中转发参数
- 标签调度/enable_if - 我很困惑