模板函数替换仅在一个参数中未使用std :: function时才起作用

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了模板函数替换仅在一个参数中未使用std :: function时才起作用相关的知识,希望对你有一定的参考价值。

我有一个带有两个模板参数的模板函数。第一个(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。模板推断不进行转换。模板推导只匹配模式。

以上是关于模板函数替换仅在一个参数中未使用std :: function时才起作用的主要内容,如果未能解决你的问题,请参考以下文章

将模板参数传递给调用成员函数的函数

Vue js 子组件中未定义的道具。但仅在其脚本中

自动模板参数:g ++ 7.3 vs clang ++ 6.0:哪个编译器正确?

从std :: function中推导返回和参数类型作为模板函数参数传递?

std::async 与共享指针模板化成员函数

使用模板化函数作为模板参数