【问题标题】:Best way to specialize function using enable_if for only some types仅对某些类型使用 enable_if 专门化功能的最佳方法
【发布时间】:2020-04-06 14:14:22
【问题描述】:

我有这段代码专门针对两种类型的打印功能,并恢复到任何其他类型的基本版本。

我的问题是,有没有办法在基本打印函数的 enable_if 中为所有专用版本输入否定大小写的情况下编写此代码?

即有没有办法删除所有!std::is_same 并且仍然具有明确的打印功能?

欢迎使用任何版本的 C++,但适用于 c++14 的版本会有所帮助。

#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);
}

【问题讨论】:

  • C++17 if constexpr 将是更具可读性的 IMO,但 C++17。如果您有适合您的条件的概念,可能是 C++20 概念,但同样不是 C++14。

标签: c++ c++14


【解决方案1】:

对于您的用例,您可以根据需要简单地为 print 函数提供重载

#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;
}

但是,如果您对 T 有更复杂的约束,那么您不能专门化 print,除非在“默认”情况下明确提供对约束的否定。

如果您可以访问 c++17,则可以将其编写在单个函数中。通常的 if-else 逻辑意味着只有在没有“专业化”的情况下才会触发基本情况。这避免了必须指定否定。

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;
}

【讨论】:

  • 抱歉,我把我的例子简单化了,在我的真实例子中,我在 is_same 中做了一些更复杂的事情,所以上面不是一个选项。
  • @Salgar 编辑了答案。它是 c++17,但可以满足您的要求,即使 enable_if 约束更复杂。
  • 重载一般比特化好。
  • @Jarod42 同意,但 OP 说他们的约束比 is_same 更复杂,所以仅仅重载是行不通的。
  • 将示例中的 std::is_same 替换为 std::is_integral/std::is_floating_point 会使专业化无法实现(因为我们不想为 float/double/@987654331 重复重载@...)。
【解决方案2】:

避免互补条件的一种方法是在重载之间给予重载优先级:

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

然后

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
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-01-08
    • 1970-01-01
    • 2014-05-13
    • 1970-01-01
    • 2021-09-10
    • 2011-06-05
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多