0 / 0 / 0
Регистрация: 28.02.2023
Сообщений: 26

Оболочка для возвращаемого значения функции и std::optional

03.03.2023, 14:02. Показов 1927. Ответов 20

Author24 — интернет-сервис помощи студентам
Добрый день!
Есть вот такой код:
Кликните здесь для просмотра всего текста
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
template <typename Func, typename Res = typename boost::function_types::result_type<Func>::type>
struct TaskWrapped
    {
        const std::function<Func> taskUnwrapped_;
        
        explicit TaskWrapped(std::function<Func> &taskUnwrapped) 
            : taskUnwrapped_(taskUnwrapped)
        {}
        explicit TaskWrapped(std::function<Func> &&taskUnwrapped) 
            : taskUnwrapped_(std::move(taskUnwrapped))
        {}
 
        template <typename... Args>
        std::optional<Res> operator()(Args &&...args) const noexcept
        //ошибка если Res = void
        {
            try
            {
                boost::this_thread::interruption_point();
            }
            catch (const boost::thread_interrupted &)
            {
                std::cerr << "thread interruption" << std::endl;
            }
            try
            {
                return taskUnwrapped_(std::forward<Args>(args)...);
            }
            catch (const std::exception &ex)
            {
                std::cerr << ex.what() << std::endl;
            }
            catch (const boost::thread_interrupted &)
            {
                std::cerr << "thread interruption" << std::endl;
            }
            catch (...)
            {
                std::cerr << "unknown error when calling the function: "
                          << boost::typeindex::type_id<Func>() << std::endl;
            }
            return std::nullopt;
        }
    };


Нужно сделать оболочку для возвращаемого значения функции, даже если оно void. Также нужно уведомить пользователя о том, что было исключение, для этого используется std::option.
Пока что так:
Кликните здесь для просмотра всего текста
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
namespace detail
    {
        template <typename Ty, typename = std::enable_if_t<std::is_same_v<Ty, void>>>
        struct non_void_return_value
        {
            using type = std::void_t<Ty>;//?????
        };
 
        template <typename Ty>
        struct non_void_return_value<Ty>
        {
            using type = Ty;
        };
 
        template <typename Ty>
        using non_void_return_value_t = typename non_void_return_value<Ty>::type;
 
        template <typename Ty>
        struct ProxyResult
        {
            using type = non_void_return_value_t<Ty>;
            std::optional<type> value_;
 
            ProxyResult(type&& value) : value_(value) {}
            ProxyResult(std::nullopt_t opt) : value_(opt) {}
            ProxyResult(void) {}
        };
    
        void foo(){}
        
        ProxyResult<void> foo2()
        {
            return foo();//error
        }
    }
0
cpp_developer
Эксперт
20123 / 5690 / 1417
Регистрация: 09.04.2010
Сообщений: 22,546
Блог
03.03.2023, 14:02
Ответы с готовыми решениями:

Ключевое слово const для возвращаемого значения из функции
Думал что это означает следующее &quot;Нельзя изменить значение которое вернет функция&quot; Но проверил и оказалось что это не так ...

Самый простой PHP код для вызова хранимой функции PostgreSQL и вывода возвращаемого значения?
Имя хранимой в PostgreSQL функции: check_login_and_password Аргументы: &quot;input_login&quot; character varying, &quot;input_pass&quot; character...

std::optional<T> при std::is_destructible_v<T> == false
Всем привет! Исследую несколько разных реализаций std::optional, и наткнулся на интересную вещь: реализация gcc допускает класть в...

20
 Аватар для zayats80888
6343 / 3514 / 1427
Регистрация: 07.02.2019
Сообщений: 8,979
03.03.2023, 17:49
Лучший ответ Сообщение было отмечено NanoCase как решение

Решение

Цитата Сообщение от NanoCase Посмотреть сообщение
Нужно сделать оболочку для возвращаемого значения функции, даже если оно void.
Что-то в этом духе
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
template<class Res>
struct my_result {
    using type = std::optional<Res>;
};
 
struct dummy {};
 
template<>
struct my_result<void> {
    using type = std::optional<dummy>;
};
 
//...
 
template <typename... Args>
typename my_result<Res>::type operator()(Args &&...args) const noexcept
{
    //...
    try
    {
        if constexpr (std::is_void_v<Res>) {
            taskUnwrapped_(std::forward<Args>(args)...);
            return dummy{};
        } else {
            return taskUnwrapped_(std::forward<Args>(args)...);
        }
    }
    //...
    return std::nullopt;
}
1
0 / 0 / 0
Регистрация: 28.02.2023
Сообщений: 26
03.03.2023, 22:02  [ТС]
Хорошее решение. Но в языке следующий код является валидным:
Кликните здесь для просмотра всего текста
C++
1
2
3
4
5
6
7
8
9
10
11
12
void foo()
{
    std::cout << "foo" << std::endl;
}
void foo2()
{
    return foo();
}
int main()
{
    foo2();
}

Думаю что можно как-то сыграть от этого при помощи SFINAE и приведений типов.
0
 Аватар для zayats80888
6343 / 3514 / 1427
Регистрация: 07.02.2019
Сообщений: 8,979
03.03.2023, 22:37
Цитата Сообщение от NanoCase Посмотреть сообщение
Думаю что можно как-то сыграть от этого при помощи SFINAE и приведений типов.
Выражением prvalue типа void нельзя инициализировать объект. Так что либо if constexpr, либо то же самое, только через специализацию какого-нибудь "инвокера".
1
0 / 0 / 0
Регистрация: 28.02.2023
Сообщений: 26
03.03.2023, 22:52  [ТС]
Понял. Спасибо за ответ!
0
19413 / 10031 / 2444
Регистрация: 30.01.2014
Сообщений: 17,697
08.03.2023, 21:51
Лучший ответ Сообщение было отмечено zayats80888 как решение

Решение

Цитата Сообщение от NanoCase Посмотреть сообщение
Думаю что можно как-то сыграть от этого
Можно сыграть.
Вот без специализаций и условий.
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
namespace detail {
 
struct Dummy {};
 
template <typename Res>
std::optional<Res> operator,(Res&& res, std::optional<Dummy>) {
    return std::forward<Res>(res);
}
 
} // detail
 
template <typename... Args>
auto operator()(Args&& ...args)
{
    using detail::Dummy;
    using Ret = decltype(taskUnwrapped_(std::forward<Args>(args)...), std::optional<Dummy>());
    
    try {
        return taskUnwrapped_(std::forward<Args>(args)...), std::optional<Dummy>();
    }
    //....
    return Ret();
}
2
0 / 0 / 0
Регистрация: 28.02.2023
Сообщений: 26
09.03.2023, 23:54  [ТС]
DrOffset, т.е. перегружая оператор запятая у нас появляется возможность вывести возвращаемое значение функции в виде шаблона и если на 7 строчке провал подстановки то мы инициализируем Ret пустышкой?
0
 Аватар для zayats80888
6343 / 3514 / 1427
Регистрация: 07.02.2019
Сообщений: 8,979
10.03.2023, 00:52
Цитата Сообщение от NanoCase Посмотреть сообщение
и если на 7 строчке провал подстановки то мы инициализируем Ret пустышкой?
Ага, только не на 7, а на 6 (точнее, на этапе формирования списка кандидатов в перегрузи).
И на 19 строчке в конструктор optional нужно передать объект Dummy, иначе результат неотличим от того, что в строке 22.
2
19413 / 10031 / 2444
Регистрация: 30.01.2014
Сообщений: 17,697
10.03.2023, 06:53
Цитата Сообщение от zayats80888
Dummy, иначе результат неотличим от того, что в строке 22.
Да, согласен, спасибо, этот момент потерялся.
1
0 / 0 / 0
Регистрация: 28.02.2023
Сообщений: 26
11.03.2023, 22:14  [ТС]
zayats80888 DrOffset, продолжаю улучшать оболочку, хочу чтобы функцию можно было вызывать из объекта, т.е. сохраняем в классе указатель на вызывающую сторону, когда хотим вызвать проверяем указатель на nullptr и вызываем соответствующий вариант функции. Но такой подход походу не работает, компилятор выдает ошибку. Можете направить меня в нужную сторону, пожалуйста

Кликните здесь для просмотра всего текста
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
struct dummy
    {
    };
 
    template <typename Res>
    std::optional<Res> operator,(Res &&res, std::optional<dummy>)
    {
        return std::forward<Res>(res);
    }
 
template <class Func, class Obj = detail::dummy*>
    struct task_wrapped
    {
        const std::function<Func> taskUnwrapped_;
        const Obj* caller_;
        
        explicit task_wrapped(std::function<Func> &taskUnwrapped, Obj* caller = nullptr) 
           : taskUnwrapped_(taskUnwrapped), caller_(caller)
        {
        }
        explicit task_wrapped(std::function<Func> &&taskUnwrapped) 
           : taskUnwrapped_(std::move(taskUnwrapped))
        {
        }
 
        template <typename... Args>
        auto operator()(Args &&...args) const noexcept
        {
            using detail::dummy;
            if constexpr(caller_)
                using Ret = decltype(caller_->taskUnwrapped_(std::forward<Args>(args)...), 
                                                                                            std::optional<dummy>());
            else 
                using Ret = decltype(taskUnwrapped_(std::forward<Args>(args)...), 
                                                                                     std::optional<dummy>());
            
            //.....
            try
            {
                if constexpr(caller_ != nullptr) 
                        return caller_->taskUnwrapped_(std::forward<Args>(args)...), 
                                                             std::optional<detail::dummy>(detail::dummy{});
                else return taskUnwrapped_(std::forward<Args>(args)...), 
                                                                          std::optional<dummy>(dummy{});
            }
           //.....
            return Ret();
        }
    };
0
19413 / 10031 / 2444
Регистрация: 30.01.2014
Сообщений: 17,697
11.03.2023, 22:16
NanoCase, у вас же есть std::function, нет нужды вводить разграничение на уровне вызова, когда можно его спрятать на уровне создания функтора.
1
0 / 0 / 0
Регистрация: 28.02.2023
Сообщений: 26
11.03.2023, 22:32  [ТС]
DrOffset, в std::function можно указывать вызывающую сторону?
0
19413 / 10031 / 2444
Регистрация: 30.01.2014
Сообщений: 17,697
11.03.2023, 22:38
Цитата Сообщение от NanoCase Посмотреть сообщение
в std::function можно указывать вызывающую сторону?
В std::bind или в лямбде можно.

Вот вариант:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
#include <iostream>
#include <optional>
#include <string>
#include <functional>
 
namespace detail {
    struct dummy
    {
    };
 
    template <typename Res>
    std::optional<Res> operator,(Res &&res, std::optional<dummy>)
    {
        return std::forward<Res>(res);
    }
    
    template <typename F>
    struct remove_function_top_const;
    template <typename R, typename ...Args>
    struct remove_function_top_const<R(Args...)> {
        using type = R(Args...);
    };
    template <typename R, typename ...Args>
    struct remove_function_top_const<R(Args...) const> {
        using type = R(Args...);
    };
}
    template <class Func>
    struct task_wrapped
    {
        const std::function<typename detail::remove_function_top_const<Func>::type> taskUnwrapped_;
 
        template <typename Obj>
        explicit task_wrapped(Func (Obj::*fptr), Obj* caller) 
            : taskUnwrapped_(std::bind(fptr, caller))
        { }
        explicit task_wrapped(std::function<Func> &&taskUnwrapped) 
            : taskUnwrapped_(std::move(taskUnwrapped))
        {
        }
 
        template <typename... Args>
        auto operator()(Args &&...args) const noexcept
        {
            using detail::dummy;
            using Ret = decltype(taskUnwrapped_(std::forward<Args>(args)...), std::optional<dummy>());
            
            //.....
            try
            {
                return taskUnwrapped_(std::forward<Args>(args)...), std::optional<dummy>(dummy{});
            }
            catch(...)
            {
            }
            return Ret();
        }
    };
 
int main()
{
    std::string a = "test";
    
    task_wrapped<char const*() const> x(&std::string::c_str, &a);
    
    std::cout << x().value();
}
https://wandbox.org/permlink/CJc6NIesab4t2Abr
1
0 / 0 / 0
Регистрация: 28.02.2023
Сообщений: 26
12.03.2023, 00:44  [ТС]
DrOffset, Вроде разобрался. Спасибо!

Добавлено через 1 час 25 минут
DrOffset, проблемка вылезла, std::bind нужны placeholders на все аргументы вызываемой функции, вроде как решается заменой bind на аналогичную лямбду, с захватом функции и caller. Вот решение близкое к правде, но он ругается на сам вызов функции в лямбде

Кликните здесь для просмотра всего текста
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
#include <iostream>
#include <optional>
#include <string>
#include <functional>
 
namespace detail {
    struct dummy
    {
    };
 
    template <typename Res>
    std::optional<Res> operator,(Res &&res, std::optional<dummy>)
    {
        return std::forward<Res>(res);
    }
    
    template <typename F>
    struct remove_function_top_const;
    template <typename R, typename ...Args>
    struct remove_function_top_const<R(Args...)> {
        using type = R(Args...);
    };
    template <typename R, typename ...Args>
    struct remove_function_top_const<R(Args...) const> {
        using type = R(Args...);
    };
}
    template <class Func>    
    struct task_wrapped;
 
    template <class R, class ...Args>
    struct task_wrapped<R(Args...)>
    {
        using Func = R(Args...);
        const std::function<typename detail::remove_function_top_const<Func>::type> taskUnwrapped_;
 
        template <typename Obj>
        explicit task_wrapped(Func (Obj::*fptr), Obj* caller) 
            : taskUnwrapped_([fptr, caller](Args &&...args){return caller->fptr(args...);})//error
        { }
        explicit task_wrapped(Func &taskUnwrapped) 
            : taskUnwrapped_(taskUnwrapped)
        {
        }
        
        auto operator()(Args &&...args) const noexcept
        {
            using detail::dummy;
            using Ret = decltype(taskUnwrapped_(std::forward<Args>(args)...), std::optional<dummy>());
            
            //.....
            try
            {
                return taskUnwrapped_(std::forward<Args>(args)...), std::optional<dummy>(dummy{});
            }
            catch(...)
            {
            }
            return Ret();
        }
    };
 
    typedef task_wrapped<int(int&, int&)> callback;
    struct str
    {   
        int sum(int& a, int& b)
        {
            return a + b;
        }
    };
 
    int sum(int& a, int& b)
{
    return a+b;
}
 
int main()
{
#ifdef i
    std::string a = "test";
    task_wrapped<char const*() const> x(&std::string::c_str, &a);
    std::cout << x().value();
#else
    str st;
    int a = 3, b = 6;
    task_wrapped<int(int&, int&)> task(&str::sum, &st);
    task(a, b);
    std::cout << a;
#endif
}
0
19413 / 10031 / 2444
Регистрация: 30.01.2014
Сообщений: 17,697
12.03.2023, 00:55
NanoCase, синтаксис вызова через указатель на метод другой. Плюс забыли forward
C++
1
taskUnwrapped_([fptr, caller](Args &&...args){return (caller->*fptr)(std::forward<Args>(args)...);})
1
0 / 0 / 0
Регистрация: 28.02.2023
Сообщений: 26
12.03.2023, 02:46  [ТС]
DrOffset, Заработало, спасибо

Добавлено через 1 час 8 минут
DrOffset, у меня ещё вопрос созрел(возможно глупый). Допустим я хочу передать в качестве параметра функции shared_ptr, который должен скопироваться в оператор() и следовательно в пользовательскую функцию. Можно ли это решить без перегрузок оператора() и тотального переписывания кода?
0
19413 / 10031 / 2444
Регистрация: 30.01.2014
Сообщений: 17,697
12.03.2023, 12:40
Цитата Сообщение от NanoCase Посмотреть сообщение
у меня ещё вопрос созрел(возможно глупый). Допустим я хочу передать в качестве параметра функции shared_ptr, который должен скопироваться в оператор() и следовательно в пользовательскую функцию. Можно ли это решить без перегрузок оператора() и тотального переписывания кода?
А в чем проблема?
C++
1
2
3
4
5
6
7
8
9
10
11
void test(std::shared_ptr<int> p) {
    // ...
}
 
int main()
{
    std::shared_ptr<int> p( new int() );
    task_wrapped<void(std::shared_ptr<int>)> x(&test);
    
    x(p);
}
0
0 / 0 / 0
Регистрация: 28.02.2023
Сообщений: 26
12.03.2023, 13:49  [ТС]
DrOffset, gcc 12.2 ошибку выдает на ваш код:

C++
1
2
error: no match for call to '(task_wrapped<void(std::shared_ptr<int>)>) (std::shared_ptr<int>&)'
error: cannot bind rvalue reference of type 'std::shared_ptr<int>&&' to lvalue of type 'std::shared_ptr<int>'
0
19413 / 10031 / 2444
Регистрация: 30.01.2014
Сообщений: 17,697
12.03.2023, 14:03
NanoCase, так не на мой, а на ваш. Вы же сами класс изменили. У вас оператор теперь не соответствует новому подходу. Надо так:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
        auto operator()(Args ...args) const noexcept
        {
            using detail::dummy;
            using Ret = decltype(taskUnwrapped_(args...), std::optional<dummy>());
            
            //.....
            try
            {
                return taskUnwrapped_(args...), std::optional<dummy>(dummy{});
            }
            catch(...)
            {
            }
            return Ret();
        }
0
0 / 0 / 0
Регистрация: 28.02.2023
Сообщений: 26
12.03.2023, 14:14  [ТС]
DrOffset, я думал вы не меняли описание враппера. дело в том что такая реализация будет принимать все по значению, даже если нужно чтобы оператор принял что то по ссылке. но я уже понял что перегружать по универсальной ссылке смысла мало. решил это добавлением дополнительного уровня косвенности, что то типо такого:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
typedef task_wrapped<void()> task;
void test(std::shared_ptr<int> p) {
    // ...
}
 
int main()
{
    std::shared_ptr<int> p( new int() );
    auto layer = [p]{test(p);};
    task x(layer);
    
    x();
    
    
}
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
raxper
Эксперт
30234 / 6612 / 1498
Регистрация: 28.12.2010
Сообщений: 21,154
Блог
12.03.2023, 14:14
Помогаю со студенческими работами здесь

Тип возвращаемого значения функции
есть класс point. в другом классе есть член функция point GetUpperLeft() { return itsUpperLeft; } эта член-функция исходя из типа...

Вывод возвращаемого значения функции
Есть функция: CREATE OR REPLACE FUNCTION block_rows_client(clID IN NUMBER, fname IN VARCHAR2) RETURN NUMBER IS CURSOR cs1 IS...

Функции (вызов и тип возвращаемого значения)
Доброй ночи! Кто может помочь мне по следующей задачей? Есть динамический массив в main(): double *m=new double ; Есть функция...

Структура в качестве возвращаемого значения функции
Добрый день! Есть вот такая программа: #include&lt;stdio.h&gt; #include&lt;stdlib.h&gt; #include&lt;string.h&gt; struct { int n; int m; }...

Ошибка с приведением возвращаемого из функции значения
Необходимо написать процедуру которая показывала бы процент детей поступивших на бюджетную форму обучения. go create procedure...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
20
Ответ Создать тему
Опции темы

Новые блоги и статьи
SwiftUI Data Flow: Передача данных между представлениями
mobDevWorks 23.03.2025
При первом знакомстве со SwiftUI кажется, что фреймворк предлагает избыточное количество механизмов для передачи данных: @State, @Binding, @StateObject, @ObservedObject, @EnvironmentObject и другие. . . .
Моки в Java: Сравниваем Mockito, EasyMock, JMockit
Javaican 23.03.2025
Как протестировать класс, который зависит от других сложных компонентов, таких как базы данных, веб-сервисы или другие классы, с которыми и так непросто работать в тестовом окружении? Для этого и. . .
Архитектурные паттерны микросервисов: ТОП-10 шаблонов
ArchitectMsa 22.03.2025
Популярность микросервисной архитектуры объясняется множеством важных преимуществ. К примеру, она позволяет командам разработчиков работать независимо друг от друга, используя различные технологии и. . .
Оптимизация рендеринга в Unity: Сортировка миллиона спрайтов
GameUnited 22.03.2025
Помните, когда наличие сотни спрайтов в игре приводило к существенному падению производительности? Время таких ограничений уходит в прошлое. Сегодня геймдев сталкивается с задачами совершенно иного. . .
Образование и практика
Igor3D 21.03.2025
Добрый день А вот каково качество/ эффективность ВУЗовского образования? Аналитическая геометрия изучается в первом семестре и считается довольно легким курсом, что вполне справедливо. Ну хорошо,. . .
Lazarus. Таблица с объединением ячеек.
Massaraksh7 21.03.2025
Понадобилась представление на экране таблицы с объединёнными ячейками. И не одной, а штук триста, и все разные. На Delphi я использовал для этих целей TStringGrid, и то, кривовато получалось. А в. . .
Async/await в Swift: Асинхронное программировани­е в iOS
mobDevWorks 20.03.2025
Асинхронное программирование долго было одной из самых сложных задач для разработчиков iOS. В течение многих лет мы сражались с замыканиями, диспетчеризацией очередей и обратными вызовами, чтобы. . .
Колмогоровская сложность: Приёмы упрощения кода
ArchitectMsa 20.03.2025
Наверное, каждый программист хотя бы раз сталкивался с кодом, который напоминает запутанный лабиринт — чем дальше в него погружаешься, тем сложнее найти выход. И когда мы говорим о сложности кода, мы. . .
PostgreSQL в Kubernetes: Подготовка кластера и настройка
Mr. Docker 20.03.2025
Когда доходит до контейнеризации баз данных и особенно таких требовательных к ресурсам системах как PostgreSQL, многие команды до сих пор колеблются, прежде чем перенести их в контейнерную. . .
C++26: Индексирование пакетов и метапрограммиро­вание
bytestream 20.03.2025
Эволюция C++ продолжается стремительными темпами – каждый новый стандарт приносит функциональность, о которой мы мечтали годами. Звучит слишком громко? Если вы когда-либо боролись с вариадическими. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2025, CyberForum.ru