使用std :: enable_if时进行优化

时间:2018-04-03 17:35:51

标签: c++ templates c++17 variadic-templates sfinae

考虑以下代码:

#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迭代两次?

2 个答案:

答案 0 :(得分:1)

  

好的,我认为评估计算了两次。但是你怎么会让它只出现一次(不使用宏)?我们应该避免在代码中重复

您可以尝试将其另存为默认值

的附加模板参数

某事

template <typename T, typename... Args, typename E = evaluate<T>>
std::enable_if_t<!E::value> foo (const T&, const Args&...);

template <typename T, typename... Args, typename E = evaluate<T>>
std::enable_if_t<E::value> foo (const T&, const Args&... args)
 {
   bar<E::size>();
   // Do whatever.
   foo(args...);
 }

template <typename T, typename ... Args, typename E>
std::enable_if_t<!E::value> foo (const T&, const Args&... args)
 {
   hit<E::size>();
   // Do whatever, but different from the previous foo overload.
   foo(args...);
 }

答案 1 :(得分:1)

你可能喜欢这个:

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的两个变体中重用常见的代码行也是可能的,这非常好。你可以相信可执行文件没有太大的不同,但我认为可维护性要好得多!