首页 > 解决方案 > 特定类型的迭代器 - 函数参数 - 元编程

问题描述

我正在尝试编写一个函数,该函数采用给定类型的(前向)迭代器。使用 SFINAE 真的很有帮助。我想出了以下(不工作)解决方案:

template<class ForwardIterator,
    typename std::enable_if<
        std::is_same<typename std::iterator_traits<ForwardIterator>::value_type, int>::value
    >::type
>
    inline void foo(ForwardIterator begin, ForwardIterator end)
{
}

在这种情况下, foo 应该可以使用std::vector<int>::iterator或仅通过提供原始 int 指针来调用。问题是,它不像我预期的那样工作。编译器(msvc 2019)总是抱怨找不到匹配的重载函数。

该代码有什么问题?

标签: c++iterator

解决方案


这不起作用的原因是因为如果enable_if得到一个真实的值,你的声明将解析为

template<class ForwardIterator, void>

这不是声明模板的有效方式。如果它改为说class = void它将有一个默认值为 void 的未命名参数,它将起作用。

template<class ForwardIterator,
class = typename std::enable_if<
    std::is_same<typename std::iterator_traits<ForwardIterator>::value_type, int>::value
>::type>

然而,这带来了另一个问题。模板参数的默认值不是其签名的一部分。因此,如果我们尝试在我们替换的地方添加一个重载,由于两个模板函数具有相同的签名,我们会得到一个错误intdouble

为了解决第二个问题,我们改为将第二个参数设为非类型参数。这将使签名相对于彼此是唯一的。

template<class ForwardIterator,
typename std::enable_if<
    std::is_same<typename std::iterator_traits<ForwardIterator>::value_type, int>::value
>::type* = nullptr>

现在,如果enable_if成功,我们会得到void*一个默认值为 of 的非类型参数,如果我们愿意nullptr,我们可以在其中添加具有不同要求的重载。enable_if

SFINAE 通常用于根据标准在不同功能之间进行选择,如果您只想限制模板static_assert很可能是更好的选择。

更容易编写,更容易阅读,并且当编译失败时,您会收到更具描述性的错误消息。


推荐阅读