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

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

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

Студворк — интернет-сервис помощи студентам
Добрый день!
Есть вот такой код:
Кликните здесь для просмотра всего текста
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
6352 / 3523 / 1428
Регистрация: 07.02.2019
Сообщений: 8,995
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
6352 / 3523 / 1428
Регистрация: 07.02.2019
Сообщений: 8,995
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
19491 / 10097 / 2460
Регистрация: 30.01.2014
Сообщений: 17,805
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
6352 / 3523 / 1428
Регистрация: 07.02.2019
Сообщений: 8,995
10.03.2023, 00:52
Цитата Сообщение от NanoCase Посмотреть сообщение
и если на 7 строчке провал подстановки то мы инициализируем Ret пустышкой?
Ага, только не на 7, а на 6 (точнее, на этапе формирования списка кандидатов в перегрузи).
И на 19 строчке в конструктор optional нужно передать объект Dummy, иначе результат неотличим от того, что в строке 22.
2
19491 / 10097 / 2460
Регистрация: 30.01.2014
Сообщений: 17,805
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
19491 / 10097 / 2460
Регистрация: 30.01.2014
Сообщений: 17,805
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
19491 / 10097 / 2460
Регистрация: 30.01.2014
Сообщений: 17,805
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
19491 / 10097 / 2460
Регистрация: 30.01.2014
Сообщений: 17,805
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
19491 / 10097 / 2460
Регистрация: 30.01.2014
Сообщений: 17,805
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
19491 / 10097 / 2460
Регистрация: 30.01.2014
Сообщений: 17,805
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
Ответ Создать тему
Опции темы

Новые блоги и статьи
изучаю kubernetes
lagorue 13.01.2026
А пригодятся-ли мне знания kubernetes в России?
сукцессия микоризы: основная теория в виде двух уравнений.
anaschu 11.01.2026
https:/ / rutube. ru/ video/ 7a537f578d808e67a3c6fd818a44a5c4/
WordPad для Windows 11
Jel 10.01.2026
WordPad для Windows 11 — это приложение, которое восстанавливает классический текстовый редактор WordPad в операционной системе Windows 11. После того как Microsoft исключила WordPad из. . .
Classic Notepad for Windows 11
Jel 10.01.2026
Old Classic Notepad for Windows 11 Приложение для Windows 11, позволяющее пользователям вернуть классическую версию текстового редактора «Блокнот» из Windows 10. Программа предоставляет более. . .
Почему дизайн решает?
Neotwalker 09.01.2026
В современном мире, где конкуренция за внимание потребителя достигла пика, дизайн становится мощным инструментом для успеха бренда. Это не просто красивый внешний вид продукта или сайта — это. . .
Модель микоризы: классовый агентный подход 3
anaschu 06.01.2026
aa0a7f55b50dd51c5ec569d2d10c54f6/ O1rJuneU_ls https:/ / vkvideo. ru/ video-115721503_456239114
Owen Logic: О недопустимости использования связки «аналоговый ПИД» + RegKZR
ФедосеевПавел 06.01.2026
Owen Logic: О недопустимости использования связки «аналоговый ПИД» + RegKZR ВВЕДЕНИЕ Введу сокращения: аналоговый ПИД — ПИД регулятор с управляющим выходом в виде числа в диапазоне от 0% до. . .
Модель микоризы: классовый агентный подход 2
anaschu 06.01.2026
репозиторий https:/ / github. com/ shumilovas/ fungi ветка по-частям. коммит Create переделка под биомассу. txt вход sc, но sm считается внутри мицелия. кстати, обьем тоже должен там считаться. . . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru