我有一个带有两个模板参数的模板函数。第一个(T
)是根据过去函数的第一个参数的类型推导出来的。第二个(ItrT
)是通过使用std::type_traits
和T
推断出来的。当我使用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
。模板推断不进行转换。模板推导只匹配模式。