仅当一个参数中未使用 std::function 时,模板函数替换才有效

Template function substitution works only if one isn't using std::function in one parameter

本文关键字:function 函数 有效 替换 std 一个 未使用 参数      更新时间:2023-10-16

我有一个带有两个模板参数的模板函数。

第一个(T(是根据第一个参数的类型推导到函数的。第二个(ItrT(是通过使用std::type_traitsT推导出来的。

当我使用ItrT作为参数的类型(参见函数bar

(时,所有类型都是隐式推导的,但是当我使用std::function<void(ItrT)>作为参数的类型(参见函数foo(时,只有在完全指定所有模板参数时才能推断出正确的类型(即使使用与函数定义中完全相同的代码(。可以想象,在模板中使用ItrT不会改变编译器推断模板的能力。

为什么不是这样呢?我需要做什么,以便可以隐式推导所有模板参数?

我正在使用C++17。

template <class T, class ItrT = typename std::iterator_traits<T>::value_type>
auto foo(T iterator, std::function<void(ItrT)> expr) -> void{
}
template <class T, class ItrT = typename std::iterator_traits<T>::value_type>
auto bar(T iterator, ItrT expr) -> void{
}
int main() {
std::vector<int> vec = {1, 2, 3};
bar(vec.begin(), 1); // Compiles!
foo(vec.begin(), [](int) {}); // Failes!
foo<decltype(vec.begin()),
std::iterator_traits<decltype(vec.begin())>::value_type>
(vec.begin(), [](int) {}); // Compiles!
}

我猜这里的混淆是围绕默认模板参数的作用。

规则不是:尝试推断一个参数。如果扣除失败,则使用默认值(如果提供(。

相反,规则是:如果参数在推导的上下文中,则推导它。如果扣除失败,则中止。如果它不在推导上下文中,并且未显式提供,请使用默认参数。换句话说,仅当参数既不在推导上下文中,也不显式提供时,才使用默认参数。

在您的两个示例中,ItrT都在推导的上下文中,因此根本不考虑默认模板参数。两者之间的区别在于,您可以从lambda推断T(您只是匹配其类型(,但不能从lambda推断function<void(T)- lambda可以转换为适当的function,但lambda不是function。模板扣除不会进行转化。模板演绎只是匹配模式。