我想在 C++ 11 中实现一个带有一对迭代器的模板函数。如果传递了一对迭代器,其值类型是任意类型的 std::pair
,则实现应该做一些特殊处理。我试图提出以下定义:
// arbitrary value types
template<typename Iter>
void process(Iter begin, Iter end) {
for (Iter iter = begin; iter != end; ++iter) {
std::cout << *iter << "\n";
}
}
// std::pair value types
template<typename Iter, typename First, typename Second,
typename std::enable_if<
std::is_same<
typename std::iterator_traits<Iter>::value_type, std::pair<First,Second>
>::value
>::type* = 0>
void process(Iter begin, Iter end) {
for (Iter iter = begin; iter != end; ++iter) {
std::cout << (*iter).first << " " << (*iter).second << "\n";
}
}
使用以下示例代码:
std::vector<int> int_vec{{1,2,3,4}};
process(int_vec.begin(), int_vec.end());
正确调用函数 process
的第一个定义。然而
std::vector<std::pair<int,std::string>> pair_vec{
{std::make_pair(1, "First"), std::make_pair(2, "Second")}};
process(pair_vec.begin(), pair_vec.end());
还调用第一个定义并产生错误消息(使用 Clang):
error: invalid operands to binary expression ('ostream' (aka 'basic_ostream<char>') and 'std::__1::pair<int, std::__1::basic_string<char> >')
为什么编译器在那种情况下不选择第二个定义?我需要如何更改重载函数?
最佳答案
在您尝试使用 enable_if
时,您引入了两个非推导上下文的模板参数。编译器无法确定 First
和 Second
是什么,因此总是从重载集中删除重载。从来没有考虑过。
我建议完全回避 SFINAE。如果您正在做的只是涉及对范围内的每个元素执行一些实际操作,只需使用函数重载:
template <class T>
void process_impl(T const& elem) {
// generic case
std::cout << elem << '\n';
}
template <class T, class U>
void process_impl(std::pair<T, U> const& elem) {
// overload for pair
std::cout << elem.first << ' ' << elem.second << '\n';
}
template <class Iter>
void process(Iter first, Iter last) {
// if C++14
std::for_each(first, last, [](auto&& elem){ process_impl(elem); });
// if C++11
using E = typename std::iterator_traits<Iter>::reference;
std::for_each(first, last, [](E elem) { process_impl(elem); });
}
关于c++ - 如何在 C++ 中为不同的迭代器 value_types 重载函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38701475/