简体   繁体   中英

Template Function Specialization for Integer Types

Suppose I have a template function:

template<typename T>
void f(T t)
{
    ...
}

Use SFINAE

// For all types except integral types:
template<typename T>
typename std::enable_if<!std::is_integral<T>::value>::type f(T t)
{
    // ...
}

// For integral types only:
template<typename T>
typename std::enable_if<std::is_integral<T>::value>::type f(T t)
{
    // ...
}

Note that you will have to include the full std::enable_if return value even for the declaration.

C++17 update:

// For all types except integral types:
template<typename T>
std::enable_if_t<!std::is_integral_v<T>> f(T t)
{
    // ...
}

// For integral types only:
template<typename T>
std::enable_if_t<std::is_integral_v<T>> f(T t)
{
    // ...
}

I would use overload resolution. That spares you from having to use the gross SFINAE hack. Unfortunately there are many areas where you can't avoid it, but this fortunately isn't one of those.

template<typename T>
void f(T t)
{
  f(t, std::is_integral<T>());
}

template<typename T>
void f(T t, std::true_type)
{ 
  // ...
}

template<typename T>
void f(T t, std::false_type)
{ 
  // ...
}

Using c++11, std::enable_if ( http://en.cppreference.com/w/cpp/types/enable_if ) can be used to do that:

template<typename T, class = typename std::enable_if<std::is_integral<T>::value>::type>
void f(T t) {...}

You can use a helper template that you can specialize like this:

#include <string>
#include <iostream>
#include <type_traits>

template <typename T, bool = std::is_integral<T>::value>
struct Foo {
        static void bar(const T& t) { std::cout << "generic: " << t << "\n"; }
};
template <typename T>
struct Foo<T, true> {
        static void bar(const T& t) { std::cout << "integral: " << t << "\n"; }
};

template <typename T>
static void bar(const T& t) {
        return Foo<T>::bar(t);
}

int main() {
        std::string s = "string";
        bar(s);
        int i = 42;
        bar(i);
        return 0;
}

output:

generic: string
integral: 42

Here is C++20 solution

template<std::integral T>
void f(T v) {
   ...
}

What about a more straightforward and better readable way by just implementing the different versions inside the function body?

    template<typename T>
    void DoSomething(T inVal) {
        static_assert(std::is_floating_point<T>::value || std::is_integral<T>::value, "Only defined for float or integral types");
        if constexpr(std::is_floating_point<T>::value) {
            // Do something with a float
        } else if constexpr(std::is_integral<T>::value) {
            // Do something with an integral
        }
    }

You dont have to worry about performance. The conditions are compile time constant and a descent compiler will optimize them away. "if constexpr" is c++17 unfortunately but you may remove "constexpr" when both versions compile without errors for both types

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM