我正在尝试编写一个采用给定类型的(前向)迭代器的函数。使用 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/