c++ - 特定类型的迭代器 - 函数参数 - 元编程

标签 c++ iterator

我正在尝试编写一个采用给定类型的(前向)迭代器的函数。使用 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)总是提示找不到匹配的重载函数。

这段代码有什么问题?

最佳答案

这不起作用的原因是因为如果 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>

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

为了解决第二个问题,我们将第二个参数设为非类型参数。这将使签名彼此独一无二。

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

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

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

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

关于c++ - 特定类型的迭代器 - 函数参数 - 元编程,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58612018/

相关文章:

c++ - Visual Studio 检查迭代器不抛出异常

c++ - 迭代器的动态大小检查?

STL 或 boost 中的 C++ range/xrange 等价物?

c++ - gSoap 不包括 Envelope 和 Body 开始标签

c++ - SFINAE 在 decltype 中使用范围解析运算符

c++ - QDir 提供了正确的文件,但显示的数量不正确

java - 使用 List<Byte> 不是个好主意吗?

c++ - 在 QAbstractTableModel 上的 setModel 之后插入数据

c++ - GetWindowLongPtr 返回失败检索用户数据

stream - 使用 PhantomData 和 unsafe 将流式迭代器作为普通迭代器处理