c++ - 在运行时询问变体中的替代方案是否满足某个概念
问题描述
我有以下代码,我尝试检测变体中的替代概念(在这种情况下为成员函数)。它冗长且相对丑陋。有没有更好的方法来做到这一点?请注意,我不想使用继承,也不想使用静态多态(假设在编译时不知道使用的引擎)。
简单来说,我正在寻找if constexpr
(仅在编译时检查概念)和std::holds_alternative
(只能检查特定类型是否为 in variant
,而不是满足概念的任何类型是否为 in variant
)的运行时组合。
#include <iostream>
#include <variant>
struct simple_engine1{
};
struct simple_engine2{
};
struct complex_engine1{
void reduce_thrust(int perc){
std::cout<<"reducing thrust " << perc << "% " << std::endl;
}
};
struct complex_engine2{
void reduce_thrust(int perc){
std::cout<<"reducing thrust " << perc << "% " << std::endl;
}
};
template< class, class = std::void_t<> >
struct has_reduce_thrust : std::false_type { };
template< class T >
struct has_reduce_thrust<T,
std::void_t<decltype( std::declval<T>().reduce_thrust(42) )>
> : std::true_type { };
static_assert(!has_reduce_thrust<simple_engine1>::value);
static_assert(!has_reduce_thrust<simple_engine1>::value);
static_assert(has_reduce_thrust<complex_engine1>::value);
struct visitor{
template<typename T>
void operator()(T& t){
dispatch(t, has_reduce_thrust<T>{});
}
template<typename T>
void dispatch(T& t, std::true_type /*has_reduce_thrust*/){
t.reduce_thrust(perc);
reduced_thrust=true;
}
template<typename T>
void dispatch(T& , std::false_type){
reduced_thrust=false;
}
int perc = 0;
bool reduced_thrust = false;
};
// tries to reduce speed by reducing thrust if engine supports it, if not
// it fires reverse engines(more expensive wrt fuel usage)
void reduce_speed(std::variant<simple_engine1, simple_engine2, complex_engine1, complex_engine2>* var_engine){
visitor v;
v.perc = 47;
std::visit(v, *var_engine);
if (v.reduced_thrust) {
std::cout << "reduced thrust\n";
} else {
std::cout << "activating reverse engines\n";
}
}
int main() {
std::variant<simple_engine1, simple_engine2, complex_engine1, complex_engine2> var_engine{simple_engine1{}};
reduce_speed(&var_engine);
var_engine = complex_engine2{};
reduce_speed(&var_engine);
var_engine = simple_engine2{};
reduce_speed(&var_engine);
var_engine = complex_engine2{};
reduce_speed(&var_engine);
}
解决方案
您可以使用以下方法大大简化访问者if constexpr
:
struct visitor{
template<typename T>
void operator()(T& t) {
if constexpr (has_reduce_thrust<T>::value) {
t.reduce_thrust(perc);
reduced_thrust = true;
}
else {
reduced_thrust = false;
}
}
int perc = 0;
bool reduced_thrust = false;
};
然后,您可以通过为 的任一分支接受任何谓词和两个函数来进一步抽象if constexpr
:
template <template <class, class... /*SFINAE friendly*/> class TypePred,
class MatchedFunc, class UnmatchedFunc>
class predicated_visitor {
public:
predicated_visitor(MatchedFunc matchedFunc, UnmatchedFunc unmatchedFunc)
: _matchedFunc(matchedFunc), _unmatchedFunc(unmatchedFunc) {}
template <typename T>
void operator()(T& t) {
if constexpr (TypePred<T>::value)
_matchedFunc(t);
else
_unmatchedFunc(t);
}
private:
MatchedFunc _matchedFunc;
UnmatchedFunc _unmatchedFunc;
};
template <template <class, class... /*SFINAE friendly*/> class TypePred,
class F1, class F2>
auto makePredicatedVisitor(F1 f1, F2 f2) {
return predicated_visitor<TypePred, F1, F2>(f1, f2);
}
我觉得生成的代码非常好:
void reduce_speed(std::variant<simple_engine1, simple_engine2, complex_engine1,
complex_engine2>* var_engine) {
int perc = 47;
bool reducedThrust = false;
auto reduceableThrustAction = [perc, &reducedThrust](auto& t) {
t.reduce_thrust(perc);
reducedThrust = true;
};
auto alternativeAction = [](auto& t) {
}; // Could explicitly set reduceThrust to false for clarity.
auto thrust_visitor = makePredicatedVisitor<has_reduce_thrust>(
reduceableThrustAction, alternativeAction);
std::visit(thrust_visitor, *var_engine);
if (reducedThrust) {
std::cout << "reduced thrust\n";
} else {
std::cout << "activating reverse engines\n";
}
}
此示例编译为与您的基本相同的汇编代码,但可以以您喜欢的任何方式重用。
我为不一致的大小写道歉...
推荐阅读
- visual-studio - 运行时的 Visual Studio 热键检测
- reactjs - AutocompleteArrayInput 显示空白条目
- c++ - 具有相对路径的 CMake 安装目标
- c++ - C++:在多个文件中定义类
- python - 继承中带/不带下划线的python变量
- vbscript - crt.Dialog.FileOpenDialog([title, [buttonLabel, [defaultFilename, [filter ]]]])
- html - 当浏览器不是全屏时,单击此处按钮上的定位关闭
- git - git 分支工作流策略
- java - 带有对象键的 HashMap
- oauth - 身份服务器 4 中的授权流程:不支持的授予类型