为什么当函数参数未定义为常量引用时存在无限递归?

Why there is an infinite recursion when function parameter is not defined as const reference?

本文关键字:存在 无限 递归 引用 常量 函数 参数 未定义 为什么      更新时间:2023-10-16

我很难理解可能导致无限递归的原因。有两点在我的问题中起作用

  1. 取决于全局函数的定义位置
  2. 我们是否将参数标记为第二个函数(全局或类成员(的 const-ref

这是代码

#include <iostream>
#include <optional>
#include <vector>
using dataType = int;
using dataTypeReturn = float;
//#define ENABLE_AFTER  // For global fncs causes inf recursion
#define CONST_REF_FUNCTION  // Causes expected behavior when !ENABLED_AFTER
#define CONST_REF_CLASS     // Causes expected behavior
#ifndef ENABLE_AFTER
#ifdef CONST_REF_FUNCTION
// Causes expected behavior
std::vector<dataTypeReturn> foo(const dataType& bar){
#else
std::vector<dataTypeReturn> foo(dataType& bar){
#endif
std::cout << "foo(const dataType& bar)" << std::endl;
return std::vector<dataTypeReturn>(10, dataTypeReturn{});
}
#endif
std::vector<dataTypeReturn> foo(const std::optional<dataType>& bar){
std::cout << "foo(const std::optional<dataType>& bar)" << std::endl;
if(bar == std::nullopt)
return {};
return foo(*bar);
}
#ifdef ENABLE_AFTER
#ifdef CONST_REF_FUNCTION
// Causes infinite recursion
std::vector<dataTypeReturn> foo(const dataType& bar){
#else
std::vector<dataTypeReturn> foo(dataType& bar){
#endif
std::vector<dataTypeReturn> foo(const dataType& bar){
std::cout << "foo(const dataType& bar)" << std::endl;
return std::vector<dataTypeReturn>(10, dataTypeReturn{});
}
#endif
class Wrapper{
public:
std::vector<dataTypeReturn> foo(const std::optional<dataType>& bar){
std::cout << "foo(const std::optional<dataType>& bar)" << std::endl;
if(bar == std::nullopt)
return {};
return foo(*bar);
}
private:
#ifdef CONST_REF_CLASS
// Causes expected behavior
std::vector<dataTypeReturn> foo(const dataType& bar){
#else
// Causes infinite recursion
std::vector<dataTypeReturn> foo(dataType& bar){
#endif
std::cout << "foo(const dataType& bar)" << std::endl;
return std::vector<dataTypeReturn>(10, dataTypeReturn{});
}
};
int main(int argc, char** argv){
std::optional<dataType> myoptional(dataType{});
foo(myoptional);
Wrapper mywrapper;
mywrapper.foo(myoptional);
return 0;
}
  1. 对于全局函数,为什么取决于我定义函数的位置是否发生递归?决定调用什么函数的编译过程是什么?
  2. 在这两种情况下,将参数标记为接收可选基础类型的函数的 const 引用不会在递归中产生,为什么?我正在查看std::optional的构造函数实现,我认为唯一可以匹配的是template < class U = value_type > constexpr optional( U&& value );但我不明白*bar如何最终成为 rvalue-ref。

您正在取消引用const optional<datatype>,您使用的是const value_type & optional::operator*() const,而不是value_type & optional::operator*()

自由函数定义仅查看在其前面声明的名称。这是在标头中声明函数的原因之一。对于成员函数,成员的定义将看到成员的所有声明。

foo(dataType& bar)不是可行的过载。如果你在定义foo(const optional<dataType>& bar)之前没有声明foo(const dataType& bar),唯一可行的重载是foo(const optional<dataType>& bar),它构造一个临时的可选。它推导出Uconst dataType &const dataType & &&被折叠为const dataType &