Best way to specialize function using enable_if for only some types

你说的曾经没有我的故事 提交于 2021-02-11 17:45:22

问题


I have this code that specializes the print function for two types, and reverts back to the base version for any other types.

My question is, is there a way to write this without having to type out the negative case for all the specialized versions in the enable_if of the base print function?

i.e. is there a way to remove all the !std::is_same and still have an unambiguous print function?

Any versions of C++ welcome, but one that works in c++14 would be helpful.

#include <iostream>

template<typename T, std::enable_if_t<!std::is_same<T, int>::value && !std::is_same<T, double>::value, int> = 42>
void print(T data)
{
    std::cout << "base:" << data << std::endl;
}

template<typename T, std::enable_if_t<std::is_same<T, double>::value, int> = 42>
void print(T data)
{
    std::cout << "double:" << data << std::endl;
}

template<typename T, std::enable_if_t<std::is_same<T, int>::value, int> = 42>
void print(T data)
{
    std::cout << "int:" << data << std::endl;
}

int main()
{
    std::string foo("foo");
    double bar = 1.2;
    int baz = 5;
    print(foo);
    print(bar);
    print(baz);
}

回答1:


For your use case, you can simply provide overloads for the print function as needed

#include <iostream>

template<typename T> 
void print(T data)
{
    std::cout << "base:" << data << std::endl;
}

void print(double data)
{
    std::cout << "double:" << data << std::endl;
}

void print(int data)
{
    std::cout << "int:" << data << std::endl;
}

However, if you have more complicated constraints on T, then you can't specialize print without explicitly providing the negation of the constraints in the "default" case.

If you have access to c++17, you can write this in a single function. The usual if-else logic means that the base case is only triggered if the "specializations" are not. This avoids having to specify the negations.

template<typename T> 
void print(T data)
{
 if constexpr(std::is_same<T, double>{})
   std::cout << "double:" << data << std::endl;
 else if constexpr(std::is_same<T, int>{})
   std::cout << "int:" << data << std::endl;
 else // if not same as int or double
   std::cout << "base:" << data << std::endl;
}



回答2:


One way to avoid complementary conditions is to give an overload priority between overload:

template <std::size_t N> struct priority_overload : priority_overload<N - 1> {};
template <> struct priority_overload<0>  {}; // Least priority

and then

template<typename T>
void print(T data, priority_overload<0>) // fallback
{
    std::cout << "base:" << data << std::endl;
}

template<typename T, std::enable_if_t<condition1<T>::value, int> = 42>
void print(T data, priority_overload<1>)
{
    std::cout << "cond1:" << data << std::endl;
}

template<typename T, std::enable_if_t<condition2<T>::value, int> = 42>
void print(T data, priority_overload<2>)
{
    std::cout << "cond2:" << data << std::endl;
}

template<typename T>
void print(T data)
{
    print(data, priority_overload<10>{});
    // Priority should be greater or equal to the one of possible overloads
}


来源:https://stackoverflow.com/questions/61061842/best-way-to-specialize-function-using-enable-if-for-only-some-types

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!