模糊函数重载[例如MAX()]

时间:2017-04-25 22:41:50

标签: c++ algorithm function templates overloading

是否可以在C ++中重载具有相似但不同模板签名的函数。

考虑max()函数。如果我想要max()函数可以接受以下三个选项中的一对,该怎么办?int*int范围,int迭代器范围。

STL将此功能分为两个功能:

那么你或者你能否在C ++中实现这种行为,如果是这样的话?

编辑:这将使max(vec.begin(), vec.end());max(vec[0], vec[1]);成功编译并找到范围的最大值和两个传递的对象的最大值。我个人认为这是不可能的,否则这两个函数将在STL中合并,但我会确认它不可行。

1 个答案:

答案 0 :(得分:1)

现在重载是不明确的,因为你没有限制它们。编译器应该如何知道第一个不应该用于迭代器?

答案很简单,你必须告诉它。幸运的是,标准定义了std::iterator_traits,您可以查询有关传递给它的迭代器类型的各种信息 - 只要它是一个迭代器。

这里的最后一点是关键:如果std::iterator_tags<T>没有嵌套的typedef iterator_category,那么T不是迭代器。因此,我们可以使用member detection using void_t来定义一个自定义特征,用于检查给定类型是否为迭代器。

在代码中,它看起来像这样:

// C++17 void_t
template <typename...>
using void_t = void;

template <typename T, typename = void>
struct is_iterator : std::false_type {
};

template <typename T>
struct is_iterator<T, void_t<typename std::iterator_traits<T>::iterator_category>> : std::true_type {
};

template <typename T>
constexpr auto is_iterator_v = is_iterator<T>::value;

为方便起见,我在这里定义了constexpr变量is_iterator_v

我们可以结合std::enable_if使用此特征,根据类型T是否为迭代器,有选择地禁用两个先前不明确的重载之一。为此,只需分别用template <typename T>template <typename T, std::enable_if_t<is_iterator_v<T>, int> = 0>替换模板声明template <typename T, std::enable_if<!is_iterator_v<T>, int> = 0>

将所有内容放在一起,代码看起来应该类似于:

// C++17 void_t
template <typename...>
using void_t = void;

template <typename T, typename = void>
struct is_iterator : std::false_type {
};

template <typename T>
struct is_iterator<T, void_t<typename   std::iterator_traits<T>::iterator_category>> : std::true_type {
};

template <typename T>
constexpr auto is_iterator_v = is_iterator<T>::value;

template<typename T, std::enable_if_t<!is_iterator_v<T>, int> = 0>
constexpr T maximum(T a, T b)
{
    return (a > b) ? a : b;
}

template<typename Iter, std::enable_if_t<is_iterator_v<Iter>, int> = 0>
constexpr Iter maximum(Iter begin, Iter end)
{
    if(begin == end) {
        return end;
    }
    auto max = begin;
    for (; begin != end; ++begin) {
        if(*begin > *max) {
            max = begin;
        }
    }
    return max;
}

您还可以在wandbox上找到工作示例。