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

问题描述 投票:0回答:1

我有一个带有两个模板参数的模板函数。第一个(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!
}

提前致谢。

c++ templates c++17
1个回答
2
投票

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

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

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

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

© www.soinside.com 2019 - 2024. All rights reserved.