我正在尝试使用 using 声明来考虑函数:
namespace n {
struct S {};
bool equal(S a, S b, std::vector<int> = {1,2}) { return false; }
}
int main() {
using ::n::equal;
using ::n::S;
/// ...
}
只要没有
std::initializer_list
作为第三个参数传递,就可以正常工作
equal(S{},S{});
equal(S{},S{},{1});
但是当
std::initializer_list
作为第三个参数传递时会中断
equal(S{},S{},std::initializer_list<int> {1, 2});
并且只考虑
std::equal
。
我很难理解为什么这不起作用的原因,并找到一个解决方案来启用这种模式。
我将对这些电话进行编号:
equal(S{},S{}); // #1
equal(S{},S{},{1}); // #2
equal(S{},S{},std::initializer_list<int>{1, 2}); // #3
因此,在
#1
和 #2
中,唯一可行的候选者是 n::equal
,因此它被调用并且一切正常。
但是在
#3
中,std::equal
突然成为候选者 - 由于明确的 std::initializer_list
参数,它被 ADL 找到。并且存在 std::equal
的过载,如下所示:
template<class InputIterator1, class InputIterator2>
constexpr bool equal(InputIterator1 first1, InputIterator1 last1,
InputIterator2 first2);
请注意,虽然模板参数被命名为InputIterator1
和
InputIterator2
,并且这些类型确实应该是输入迭代器,但算法本身不受约束,因此它被认为是可行的候选者。 在
n::equal
和
std::equal
之间,后者是更好的匹配 - 所有参数都完全匹配,而对于
n::equal
需要从
std::initializer_list<int>
到
std::vector<int>
的显式转换。因此,选择了
std::equal
- 然后将无法编译,因为这些类型都不是迭代器。
std::initializer_list<int>
而只是手动传递
std::vector<int>
。或者,您可以添加额外的
n::equal
重载来处理这种情况:
bool equal(S a, S b, std::vector<int> = {1,2});
bool equal(S a, S b, std::initializer_list<int> xs) {
return equal(a, b, std::vector<int>(xs));
}