编译器无法推断出模板函数的类型?

问题描述

我有以下代码示例:

express

此处编译器错误显示以下消息:

template<typename T>
void print(T t) {
    std::cout << t << std::endl;
}

template<typename Key,typename Value,typename F>
void traverse(std::map<Key,Value>& m,F f) {
    for (auto&& [key,value] : m) {
        f(value);
    }
}

int main()
{
    std::map<int,std::string> M;
    // initializing the map
    traverse(M,print);
}

显式Could not deduce template argument for 'F' 解决了这个问题。
我的问题确实是为什么编译器无法推断出打印功能的模板类型?

据我了解,所有编译时间信息均可用。

解决方法

模板自变量推导基于函数的模板参数,函数的签名以及所提供的自变量的类型进行。而已。即使忽略print是模板函数的事实(因此没有可用于推导的类型),traverse的签名中也没有任何东西可以使编译器有任何想法推断的类型将是print<std::string>的类型。任何此类信息都将在函数的定义中。

traverse实例化后尚不存在且不能存在的定义。而且,只有具有模板参数,您才能实例化模板。模板自变量推导旨在弄清楚哪种方法。

而且,如前所述,print不是函数;它是 template 的名称。它没有类型。它甚至不是功能。它是一种基于模板参数生成函数的方法。即使您试图将print传递给不是模板的函数,该代码仍然无法使用。编译器只能在调用时对函数执行模板参数推导,而不能在将它们作为函数参数传递时进行。在所有非推论情况下,您都必须直接提供模板参数。

,

并非所有必需的编译时间信息都可用,尤其是print模板实例化参数也不可用。

traverse是一个函数模板,它接受第二个参数的任何参数类型,但是名称print本身并不表示任何特定类型,仅表示模板名称,并且编译器无法推断您打算将模板传递给模板的哪个具体实例。

显然,您希望编译器从print<std::string>类型的模板参数推导print的{​​{1}}实例。为此,您可以在M模板中进行指定,使traverse参数的类型取决于f的类型,例如,删除不相关的m,像这样:

typename F
,

编译器无法推论print的类型,因为它忽略了traverse的主体和所有不相关的参数。当您调用traverse(M,print)时,编译器将尝试确定打印类型,就像您刚刚调用此example一样:

template<typename F>
void example(F f);

example(print);

您可以通过以下方式更改traverse的类型来编译代码:

template<typename Key,typename Value>
void traverse(std::map<Key,Value>& m,void(*f)(Value));

或通过指定特定的print

    traverse(M,print<std::string>);