考虑这段代码:
#include <iostream>
#include <type_traits>
template <std::size_t N> void bar() { std::cout << "bar<" << N << ">() called.\n"; }
template <std::size_t N> void hit() { std::cout << "hit<" << N << ">() called.\n"; }
template <typename T> struct evaluate : std::bool_constant<std::is_integral_v<T>> {
static constexpr std::size_t size = sizeof(T); // Simplified for illustration only.
};
void foo() { }
template <typename T, typename... Args>
std::enable_if_t<!evaluate<T>::value> foo (const T&, const Args&...);
template <typename T, typename... Args>
std::enable_if_t<evaluate<T>::value> foo (const T&, const Args&... args) {
bar<evaluate<T>::size>();
// Do whatever.
foo(args...);
}
template <typename T, typename... Args>
std::enable_if_t<!evaluate<T>::value> foo (const T&, const Args&... args) {
hit<evaluate<T>::size>();
// Do whatever, but different from the previous foo overload.
foo(args...);
}
int main() {
foo (5, "hello", true);
}
Output:
bar<4>() called.
hit<6>() called.
bar<1>() called.
如何重写上面的内容使得 evaluate<T>
每次 foo 迭代只需要计算一次而不是两次?
最佳答案
你可能喜欢这个:
template <std::size_t N> void bar() { std::cout << "bar<" << N << ">() called.\n"; }
template <std::size_t N> void hit() { std::cout << "hit<" << N << ">() called.\n"; }
template <typename T>
struct evaluate : std::bool_constant<std::is_integral_v<T>>
{
static constexpr std::size_t size = sizeof(T); // Simplified for illustration only.
};
void foo() { }
template <typename T, typename... Args>
void foo( const T&, const Args&... args)
{
using X = evaluate<T>;
if constexpr ( X::value )
{
bar<X::size>();
}
else
{
hit<X::size>();
}
foo( args... );
}
int main() {
foo (5, "hello", true);
}
它只“调用”一次 evaluate<T>
,这并不重要,但可能更容易阅读。所有模板代码仅在实例化过程中使用,这只是个人喜好问题。
正如您提到的 c++17
你可以使用 constexpr if
在您的示例中完全摆脱 SFINAE。这也使得在 foo 的两种变体中重用公共(public)代码行成为可能,这非常好。您可以相信,可执行文件不会有太大差异,但我认为可维护性要好得多!
关于c++ - 使用 std::enable_if 时进行优化,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49636070/