【问题标题】:Ambiguous Function Overloads [e.g. max()]模棱两可的函数重载[例如最大限度()]
【发布时间】:2017-04-25 22:41:49
【问题描述】:

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

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

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

那么你能或不能在 C++ 中实现这种行为吗?如果可以,如何实现?

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

【问题讨论】:

  • 是的,有可能。你试过了吗?你在哪里遇到麻烦了?
  • 只要函数调用不干扰同名函数调用,重载就不会有任何问题
  • 你不能实现一个看起来像这样int max( const int * p );的函数,因为没有办法知道p指向多少个整数,所以你会想要int max( const int * begin, const int * end );和类似的东西迭代器。
  • @aschepler cpp.sh/8grre 错误:重新定义'模板 Iter Algorithm::maximum(Iter, Iter)'
  • @ChrisHutchison 但它们确实会干扰,因为它们具有相同的签名,有没有办法避免这种情况?

标签: c++ algorithm function templates overloading


【解决方案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 &lt;typename T&gt; 分别替换为 template &lt;typename T, std::enable_if_t&lt;is_iterator_v&lt;T&gt;, int&gt; = 0&gt;template &lt;typename T, std::enable_if&lt;!is_iterator_v&lt;T&gt;, int&gt; = 0&gt;

将所有内容放在一起,代码应该如下所示:

// 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 上找到工作示例。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-04-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-03-13
    • 1970-01-01
    • 1970-01-01
    • 2015-01-12
    相关资源
    最近更新 更多