【问题标题】:Template argument deduction Doesn't Work for Function Template <unresolved overloaded function type>模板参数推导不适用于函数模板<未解析的重载函数类型>
【发布时间】:2021-11-27 15:28:42
【问题描述】:

我试图了解模板参数推导在 C++ 中的工作原理。所以写出不同的例子。下面给出了一个这样的例子,它不起作用,我不明白为什么:

#include<iostream>
template<int var, typename T>
void func (T x)
{
    std::cout<<x<<std::endl;
}

template<typename T>
void SomeFunc(T a)
{
    a(6);
}
int main()
{
    
    
    func<5, int>(10);//this work as expected
    func<5>(20);//this works as well using template argument deduction
    
   
    SomeFunc(func<5,int>) ;//this works as well
    
    
    //the next two calls doesn't work
    
    SomeFunc(func<5>);//this doesn't work. Why doesn't template argument deduction works here
    SomeFunc(func<5>(20));//this doesn't work either.
   
    
    return 0;
}

在上面的例子中,SomeFunc(func&lt;5&gt;); 语句不起作用。我的想法是,当编译器尝试实例化SomeFunc&lt;&gt; 时,它需要它的模板类型参数。但是我们已经将func&lt;5&gt; 作为函数调用参数传递了,而没有实际调用(将调用参数指定给func 本身)func 所以没有办法推导出第二个参数,所以它不起作用。我的第一个问题是我对为什么这个调用失败的分析正确吗?如果没有,那为什么它不起作用。

接下来在SomeFunc(func&lt;5&gt;(20)); 语句中,我将函数调用参数20 指定为func,这在之前的调用中没有指定。但这种说法仍然不起作用。 为什么会这样

在阅读模板参数推导时,我还发现了以下声明:

扣费仅适用于即时通话。

但我不明白上面引用的陈述是什么意思。它可能与完整类型或不完整类型用作模板参数的事实有关,但我不确定。

【问题讨论】:

  • func 返回void。您不能拥有 SomeFunc 正在尝试做的 void 类型的对象。
  • 但是SomeFunc(func&lt;5,int&gt;) ; 是如何工作的呢?这里我们有相同的函数模板func,它返回void
  • func&lt;5,int&gt; 不调用该函数。相反,它命名了一个函数对象,该对象衰减为一个函数指针,其地址指向func&lt;5,int&gt; 函数。
  • func&lt;5&gt; 不起作用,因为编译器在传递函数指针时不知道第二个模板参数是什么。当您调用该函数时,它会返回 void,因此会中断。 func&lt;5, int&gt; 有效,因为它将func&lt;5,int&gt; 函数指针传递给SomeFunc

标签: c++ c++11 templates c++17 template-argument-deduction


【解决方案1】:

func&lt;5&gt; 是对func 的无效调用,因为即使对于采用 0 参数的函数,您也必须使用括号来调用函数。至于第二个错误,func&lt;5&gt;(20) 是有效的,因为编译器能够从函数的参数类型推导出 T。但是,您不能有 void 变量。因此,使用 void 值调用 SomeFunc 是无效的,因为 a 不能是 void 参数。

static_assert(std::is_same_v<decltype(func<5>(20)), void>);

SomeFunc(func<5>(20)); // T is deduced as void

【讨论】:

    【解决方案2】:
    • SomeFunc(func<5,int>);
      

      您将一个指针传递给函数func&lt;5,int&gt;,然后T 变为void(*)(int),这很好。当您使用函数指针a 调用它所指向的函数时,它也可以在内部 SomeFunc 工作。

    • SomeFunc(func<5>);
      

      不能扣除。编译器无法期待在 SomeFunc 内部看到您将调用 a(6),因此它必须实例化 func&lt;5,int&gt; 并让 a 指向它。

    • SomeFunc(func<5>(20));
      

      在这里,您实际上调用了func&lt;5,int&gt;(带有参数20)并将该调用的返回值传递给SomeFuncfunc&lt;5,int&gt; 没有返回值,因为它的 voidvoid a; 无效。如果它有效,那么下一个问题将是您尝试在SomeFunc 中调用aSomeFunc 的参数必须是某种可调用对象,否则 a(6); 将失败。

    【讨论】:

    • 好的,你的回答很有道理。在将其标记为正确之前,我有一个疑问。当我写SomeFunc(func&lt;5,int&gt;); 时,我们将一个指针 传递给函数模板func&lt;5,int&gt;。我的问题是,当我们编写 func&lt;5,int&gt; 时,这是否意味着我们实例化这个函数模板。本质上,我想知道的是,当我们获取函数模板的地址时,该函数模板是否被实例化?
    • 是的,func&lt;5,int&gt; 实例化了实际的函数,因此传递给SomeFunc 的不是指向函数模板的指针,而是指向真实函数的指针。 Demo
    • @JasonLiam ... 和 here are 更多选项。
    猜你喜欢
    • 2018-12-05
    • 2011-07-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-05-23
    相关资源
    最近更新 更多