我希望这个主题能反映我想在这里问的问题......我尽力了。
我们必须根据几个运行时条件设置某些变量。我们总是选择如果..else 语句,但我发现它们太麻烦了,特别是考虑到可能有几个条件。我尝试使用 c++11/17 功能开发一些东西,并提出了以下内容。
所以我的问题是关于:性能和可读性,你更喜欢使用以下吗?
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; });
函数的可读性是一个问题,您可以随时使用 C++17 :)摆脱很多 SFINAE 魔法
#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;
}
对于发布版本,性能应该完全相同,而在未优化的版本上可能会慢一些。例如,上面的代码通过优化编译为 gcc/clang 上的return 222
。不过,编译时间可能会受到一些影响。
我不喜欢像这样的巨大可变参数函数调用,但有时它们是值得的,因为它们在整个代码库中节省了大量键入。如果不了解您的真实用例,就很难说。
老实说,我更喜欢if-else
语句或?:
运算符。更易于调试或解释故障转储。非C++开发人员或初学者开发人员更易于阅读。而且没有坚实的缺点。