为什么编译器无法推断返回类型?

Why can't compiler deduce the return types?

本文关键字:返回类型 编译器 为什么      更新时间:2023-10-16

如果返回类型恰好是模板参数,编译器不能推断函数的返回类型吗?或者我在遵循代码时犯了错误。

#include <iostream>
template <typename TT>                                                                                                                                                                                                                                                                                                                                                                        
TT retBoolFail(bool a) {                                                                                                                                                                                                                                                                                                                                                                      
return true;                                                                                                                                                                                                                                                                                                                                                                              
}
template <typename TT>                                                                                                                                                                                                                                                                                                                                                                        
void retBoolSuccess(bool a, TT& ret) {                                                                                                                                                                                                                                                                                                                                                        
ret = true;                                                                                                                                                                                                                                                                                                                                                                               
return;                                                                                                                                                                                                                                                                                                                                                                                   
}
int main() {                                                                                                                                                                                                                                                                                                                                                                                  
bool ret;                                                                                                                                                                                                                                                                                                                                                                                 
retBoolSuccess(true, ret);  // Success                                                                                                                                                                                                                                                                                                                                                    
retBoolFail(true);          // Failure                                                                                                                                                                                                                                                                                                                                                    
return 0;                                                                                                                                                                                                                                                                                                                                                                                 
}

行"RetBoolFail(true)"失败,并出现以下错误。

-*- mode: compilation; default-directory: "~/work/c++/tupleTemplate/" -*-
Compilation started at Thu Mar 21 16:52:50
g++ -c simpletemp.cc  -std=c++1z -g; g++ -o simpletemp simpletemp.o
simpletemp.cc: In function ‘int main()’:
simpletemp.cc:17:21: error: no matching function for call to ‘retBoolFail(bool)’
retBoolFail(true);          // Failure
^
simpletemp.cc:4:4: note: candidate: template<class TT> TT retBoolFail(bool)
TT retBoolFail(bool a) {
^
simpletemp.cc:4:4: note:   template argument deduction/substitution failed:
simpletemp.cc:17:21: note:   couldn't deduce template parameter ‘TT’
retBoolFail(true);          // Failure
^
Compilation finished at Thu Mar 21 16:52:50

谢谢。

不,扣除只发生在参数列表中。可以改用auto,也可以仅将其设置为具有硬编码返回类型的非模板函数。

当模板名称用作要调用的函数时,模板参数推导仅使用函数参数和模板函数签名,而不使用函数体。

此规则在标准中难以更改的一个原因是,如果名称重载,则工作方式如何。 更全面的情况是:

  1. 名称查找查找一组函数和函数模板。

  2. 对于集合中的每个函数模板,模板参数由显式模板参数、推导和/或默认模板参数确定。 如果推导失败,或者如果将确定的模板参数替换为函数类型执行无效操作,则函数模板只是从重载集中丢弃为不可行。

  3. 对于每个函数签名(无论是否来自模板),都会进行检查以查看函数参数和函数参数是否匹配。否则,该功能不可行,将从重载集中丢弃。

  4. 重载分辨率比较其余可行函数。 对于大多数过程,模板中的函数类型被视为非模板函数,但有一些特定于函数模板专用化的最终决胜规则。

  5. 如果重载解析选择了函数模板专用化,并且上下文是需要存在函数定义的上下文,则还会实例化函数体以生成该定义。 如果将模板参数参数替换到函数体中执行无效操作,则程序格式不正确。

因此,此处区分函数模板的函数类型是否和实例化的时间,以及两种情况下模板参数使用无效的结果。 从功能体推断会混淆这一点。

但在其他一些情况下,函数模板返回类型中的模板参数可能涉及模板参数推导。 (此列表可能并不详尽。

如果从函数模板名称(或其指针大小写的地址)初始化指向函数的指针或对函数的引用,则返回类型将参与模板参数推导:

template <typename TT>
TT f();
unsigned int (&func_ptr)() = f; // TT deduced as unsigned int
int g(double (*)());
int g_of_f = g(f);  // TT deduced as double

类或类模板可以具有转换函数模板。 然后,具有该类类型的表达式的某些用法可以隐式使用该模板,这需要在其返回类型中推导模板参数(这也是其声明中operator关键字后面的内容)。

class A {
public:
template <typename TT>
operator std::shared_ptr<TT>() const;
};
std::shared_ptr<int> p = A{}; // TT deduced as int

另请注意,使用"占位符类型"作为其返回类型的函数或函数模板(返回类型包含关键字auto)确实从主体的return语句(由于"if constexpr"而未跳过)推断其返回类型。 虽然没有模板头的函数仍然只是一个具有特定类型的函数,而不是函数模板,并且此推导是与任何模板参数推导分开的步骤。

auto retBool(bool a) {
return true;       // return type is bool
}
template <typename T>
constexpr const auto* constify(T* ptr) {
return ptr;       // return type is const T* (T* if T is already const)
}

类型推导不适用于仅返回类型的函数模板参数。

在您的情况下,您必须使用

retBoolFail<bool>(true);

您必须提示编译器才能推断返回类型的类型。即使在函数模板中使用auto,仍需要在调用站点提示编译器。