Почему существует бесконечная рекурсия, когда параметр функции не определен как константная ссылка? - PullRequest
0 голосов
/ 28 мая 2020

У меня проблемы с пониманием причины бесконечной рекурсии. В моей проблеме играют роль два момента

  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. В обоих случаях маркировка параметра как константная ссылка для функции, которая получает базовый тип необязательного, не возникает в рекурсии, почему? Я смотрел на реализации конструктора std::optional, и единственное, что могло соответствовать, я думаю, это template < class U = value_type > constexpr optional( U&& value );, но я не понимаю, как *bar заканчивается как rvalue-ref.

1 Ответ

3 голосов
/ 28 мая 2020

Вы разыменовываете const optional<datatype>, вы используете const value_type & optional::operator*() const, а не value_type & optional::operator*().

Свободное определение функции смотрит только на имена, объявленные перед ним. Это одна из причин наличия в заголовках объявлений функций. В случае функции-члена определения членов видят все объявления членов.

foo(dataType& bar) не является допустимой перегрузкой. Если вы не объявили foo(const dataType& bar) перед определением foo(const optional<dataType>& bar), единственной жизнеспособной перегрузкой будет foo(const optional<dataType>& bar), которая создает временную опцию. Он выводит U как const dataType &, а const dataType & && равно свернуто до const dataType &

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...