C++ 递归变量函数调用对简单if..else语句的性能
我希望这个主题反映了我想问的问题。。。我尽了最大的努力 我们必须根据几个运行时条件设置某些变量。我们总是使用if..else语句,但我发现它们太麻烦了,特别是考虑到可能有几个条件。我尝试使用c++11/17特性开发一些东西,并得出以下结论 因此,我的问题是:性能和可读性,您愿意使用以下选项吗C++ 递归变量函数调用对简单if..else语句的性能,c++,c++11,c++17,variadic-templates,variadic-functions,C++,C++11,C++17,Variadic Templates,Variadic Functions,我希望这个主题反映了我想问的问题。。。我尽了最大的努力 我们必须根据几个运行时条件设置某些变量。我们总是使用if..else语句,但我发现它们太麻烦了,特别是考虑到可能有几个条件。我尝试使用c++11/17特性开发一些东西,并得出以下结论 因此,我的问题是:性能和可读性,您愿意使用以下选项吗 template <typename DST, typename... Ts> void SetValue(DST& dst, Ts&&... ts) { Check
template <typename DST, typename... Ts>
void SetValue(DST& dst, Ts&&... ts)
{
CheckAndSetVal(dst, std::forward<Ts>(ts)...);
}
template <typename DST>
void CheckAndSetVal(DST&) {}
template <typename DST, typename T1, typename T2, typename... Ts>
std::enable_if_t<std::is_same_v<DST, T2> > CheckAndSetVal(DST& dst, T1&& cond, T2&& val, Ts&&... ts)
{
if (cond())
dst = val; // Assign the value here ...
else
CheckAndSetVal(dst, std::forward<Ts>(ts)...);
}
template <typename DST, typename T1, typename T2, typename... Ts>
std::enable_if_t<!std::is_same_v<DST, T2> > CheckAndSetVal(DST& dst, T1&& cond, T2&& val, Ts&&... ts)
{
if (cond())
dst = val(); // Assign the value using this functor ..
else
CheckAndSetVal(dst, std::forward<Ts>(ts)...);
}
int i;
//
// In practive though the conditions are not as trivial as they look here.
//
SetValue(i, []() { return false; }, 444
, []() { return false; }, 999
, []() { return true; }, []() { return 222; });
模板
无效设置值(DST和DST、Ts和…Ts)
{
CheckAndSetVal(dst、std::forward(ts)…);
}
模板
void CheckAndSetVal(DST&){}
模板
std::启用检查和设置值(DST&DST、T1&cond、T2&val、Ts&;Ts)
{
if(cond())
dst=val;//在此处赋值。。。
其他的
CheckAndSetVal(dst、std::forward(ts)…);
}
模板
std::如果>CheckAndSetVal(DST&DST、T1&cond、T2&val、Ts&val)则启用
{
if(cond())
dst=val();//使用此函子赋值。。
其他的
CheckAndSetVal(dst、std::forward(ts)…);
}
int i;
//
//在实践中,虽然条件并不像这里看起来的那么简单。
//
SetValue(i,[](){return false;},444
,[](){返回false;},999
,[](){return true;},[](){return 222;});
如果该函数的可读性是一个问题,那么您可以使用C++17:)摆脱很多SFINAE魔法
#包括
#包括
模板
无效设置值(目标和输出、条件和条件、值和值、Ts和…Ts)
{
if(cond())
{
如果constexpr(std::is\u invocable\u v)
{
out=value();
}
其他的
{
out=值;
}
}
其他的
{
如果constexpr(sizeof…(Ts)!=0)
{
设置值(输出,标准::正向(ts)…);
}
}
}
int main()
{
int i;
SetValue(i,[](){return false;},444,
[](){返回false;},999,
[](){return true;},[](){return 222;});
返回i;
}
对于发布版本,性能应该完全相同,对于未优化的版本,性能可能会稍慢一些。例如,上面的代码在gcc/clang上编译为return222
,并进行了优化。不过,编译时可能需要一些时间
我不喜欢这种巨大的可变函数调用,但有时它们是值得的,因为它们在整个代码库中节省了大量输入。在不了解实际用例的情况下,很难说清楚。如果该函数的可读性是一个问题,那么您可以使用C++17:)摆脱很多SFINAE魔法
#包括
#包括
模板
无效设置值(目标和输出、条件和条件、值和值、Ts和…Ts)
{
if(cond())
{
如果constexpr(std::is\u invocable\u v)
{
out=value();
}
其他的
{
out=值;
}
}
其他的
{
如果constexpr(sizeof…(Ts)!=0)
{
设置值(输出,标准::正向(ts)…);
}
}
}
int main()
{
int i;
SetValue(i,[](){return false;},444,
[](){返回false;},999,
[](){return true;},[](){return 222;});
返回i;
}
对于发布版本,性能应该完全相同,对于未优化的版本,性能可能会稍慢一些。例如,上面的代码在gcc/clang上编译为return222
,并进行了优化。不过,编译时可能需要一些时间
我不喜欢这种巨大的可变函数调用,但有时它们是值得的,因为它们在整个代码库中节省了大量输入。如果不知道您的实际用例,很难判断。老实说,我更喜欢
if else
语句或?:
操作符。
易于调试或解释崩溃转储。
非C++开发人员或初学者更容易阅读。
而且没有明显的缺点。老实说,我更喜欢
if-else
语句或?:
操作符。
易于调试或解释崩溃转储。
非C++开发人员或初学者更容易阅读。
而且没有明显的缺点。谢谢您的快速回复。首先,我很惊讶这会编译,因为作为可调用函数和值的用法似乎在同一个函数中。这是否意味着只有if..else部分中的一个被编译成了目标代码?如果不是,那么“out=value()”和“out=value”怎么可能在同一个函数中?@lightsunray:对于常规的
If
,这将是有问题的,但是我们在这里使用If constexpr
,它“丢弃”了错误的分支。@Asu:这也清楚地表明out
可能保持不变(因此无法在函数中按原样返回它)@Asu:谢谢。有“if constexpr”的那个对我来说是全新的。谢谢你的快速回复。首先,我很惊讶这会编译,因为作为可调用函数和值的用法似乎在同一个函数中。这是否意味着只有if..else部分中的一个被编译成了目标代码?如果不是,那么“out=value()”和“out=value”怎么可能在同一个函数中?@lightsunray:对于常规的If
,这将是有问题的,但是我们在这里使用If constexpr
,它“丢弃”了错误的分支。@Asu:这也清楚地表明out
可能保持不变(因此无法在函数中按原样返回它)@Asu:谢谢。带有“if constexpr”的那个对我来说是全新的。为了可读性,我可能会将{cond,val}
分组到它自己的类中,一个“lazyOptional”。对于C++11,它意味着使用类似于std::pairforreadability的std::function
,我可能会将{cond,val}
分组到它自己的类中,一个“lazyOptional”。在C++11中,它意味着使用std::function
和std::pairw之类的东西。在可读性方面,简单的if..else对于单个变量来说是不可替代的。但在我的用例中,我有se
#include <functional>
#include <type_traits>
template<class DestT, class CondT, class ValueT, class... Ts>
void SetValue(DestT& out, CondT&& cond, ValueT&& value, Ts&&... ts)
{
if (cond())
{
if constexpr (std::is_invocable_v<ValueT>)
{
out = value();
}
else
{
out = value;
}
}
else
{
if constexpr (sizeof...(Ts) != 0)
{
SetValue(out, std::forward<Ts>(ts)...);
}
}
}
int main()
{
int i;
SetValue(i, []() { return false; }, 444,
[]() { return false; }, 999,
[]() { return true; }, []() { return 222; });
return i;
}