c++ - 检查元组中的项目是否包含特定方法
问题描述
我有一个元组,我正在尝试为元组中的每个对象调用initialize()。现在,某些对象可能不包含该功能。我知道我可以通过使用 C++20要求功能来检查类是否包含给定函数来完成这项工作。不幸的是,我正在使用 MSVC,但它还不支持。
有可能写得不一样吗?我可以使用 C++20 但它应该在 MSVC 上编译
template <class... Args>
struct CustomTuple : std::tuple<Args...> {
// Calls "initialize() for each item inside the tuple if that function exists"
template <std::size_t I = 0>
auto initialize() {
std::decay_t<decltype(std::get<I>(*this))> item;
constexpr bool has_initialize = requires() { // doesnt't work on MSVC
item.initialize();
};
if constexpr (has_initialize) {
std::get<I>(*this).initialize();
}
if constexpr (I + 1 != sizeof...(Args)) {
initialize<I + 1>();
}
}
};
解决方案
如果您还没有访问权限requires
,那么您将不得不使用 SFINAE 并编写一个类型特征来检测是否initialize()
是可调用的成员函数。
这可以用 来完成std::void_t
,尽管有点尴尬:
#include <type_traits> // std::void_t
#include <utility> // std::declval
template <typename T, typename = void>
struct has_initialize_impl : std::false_type {};
template <typename T>
struct has_initialize_impl<T,
std::void_t<decltype(std::declval<T&>().initialize())>
> : std::true_type {};
template <typename T>
inline constexpr auto has_initialize = has_initialize_impl<T>::value;
上述特征检查是否有任何可变引用T&
可以调用名为initialize()
. 如果表达式格式正确,则has_initialized
计算结果为true
; 否则,它的计算结果为false
。
然后可以将其与您的其余代码一起使用,只需稍作更改:
template <class... Args>
struct CustomTuple : std::tuple<Args...> {
// Calls "initialize() for each item inside the tuple if that function exists"
template <std::size_t I = 0>
auto initialize() {
// Note: no need to construct a temporary/unused 'item' type,
// we can just use 'tuple_element' here to get the type
using element_type = typename std::tuple_element<I, std::tuple<Args...>>::type;
if constexpr (has_initialize<element_type >) {
std::get<I>(*this).initialize();
}
if constexpr (I + 1 != sizeof...(Args)) {
initialize<I + 1>();
}
}
};
如果您认为您可能有更多需要检测功能的情况,但仍不requires
支持 C++20,那么可能值得考虑将“检测到”-idiom + 样板代码添加到您的代码中,这可以在cppreference上找到。
这与实际行为相同std::void_t
,但如果经常需要会更方便。这仍然比 c++20's 更迟钝requires
,但如果你的编译器不支持它,你就没有太多选择了。
使用is_detected_v
,您只需为需要验证的任何表达式定义模板类型别名,然后将其简单地传递给特征。
例如,上述解决方案可以简洁地解决为:
template <typename T>
using detect_initialize = decltype(std::declval<T&>().initialize());
...
if constexpr (is_detected_v<detect_initialize, decltype(item)>) {
...
}
推荐阅读
- c# - RFID 阅读器中的 C# 多线程
- docker - 如何运行 CKAN docker 映像?
- c# - 编写一个(非常)通用的相等比较器
- video - FFMPEG 在处理 MOV 文件时失败
- node.js - 使用docker时winston日志文件在哪里
- ios - iOS14 navigationItem.largeTitleDisplayMode = .always 不工作
- azure - 部署在 Azure 虚拟机上的 Web 应用:持久性 VS 临时磁盘
- javascript - 在邮递员中,我如何根据另一个测试是否通过或失败来运行新测试?
- python - Python:如何在烧瓶中显示 sns.catplot()?
- html - 包含掩码的内联 SVG 渲染不正确