Форум программистов, компьютерный форум, киберфорум
C++
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.94/18: Рейтинг темы: голосов - 18, средняя оценка - 4.94
 Аватар для zayats80888
6352 / 3523 / 1428
Регистрация: 07.02.2019
Сообщений: 8,995

Непонятное предупреждение компилятора

27.01.2021, 21:16. Показов 3406. Ответов 9

Студворк — интернет-сервис помощи студентам
Прошу объяснить проедупреждение, которое генерирует Clang для этого кода:
code
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
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
// message.hpp
#pragma once
 
#include <utility>
#include <variant>
 
#ifdef UNHANDLED_MSG_WARN
    #error "UNHANDLED_MSG_WARN macro conflict"
#endif
 
#if defined(DEBUG) || defined(_DEBUG)
    #include <iostream>
    #include <typeinfo>
    #include <boost/core/demangle.hpp>
    #define UNHANDLED_MSG_WARN(T) \
        ::std::cout << "unhandled message: " \
                    << ::boost::core::demangle(typeid(T).name()) \
                    << '\n';
#else
    #define UNHANDLED_MSG_WARN(T)
#endif
 
namespace msg
{
    namespace detail
    {
        template <class ... Ts>
        struct HandlerImpl;
        
        template <class T>
        struct HandlerImpl<T>
        {
            using MessageType = T;
            
            virtual void onMessage(const MessageType &) { UNHANDLED_MSG_WARN(MessageType) }
        };
        
        template <class T, class ... Ts>
        struct HandlerImpl<T, Ts...> : HandlerImpl<Ts...>
        {
            using MessageType = T;
            using Base = HandlerImpl<Ts...>;
            
            using Base::onMessage;
            
            virtual void onMessage(const MessageType &) { UNHANDLED_MSG_WARN(MessageType) }
        };
        
               
        template <template <class...> class Variant, class ... Ts>
        HandlerImpl<Ts...> hanlerTypes(Variant<Ts...> &&);
        
        template <class Variant,
                  class T = decltype(hanlerTypes(::std::declval<Variant>()))>
        struct HandlerBase
        {
           using Type = T;
        };
    } // namespace detail
    
    template <class ... Ts>
    using Message = ::std::variant<Ts...>;
    
    template <class Message>
    class Handler
        : private detail::HandlerBase<Message>::Type
    {
        using Base = typename detail::HandlerBase<Message>::Type;
        using Base::onMessage;
    public:
 
        virtual ~Handler() = default;
    
        void processMessage(const Message & mess)
        {
            ::std::visit([this](auto const & m){ onMessage(m); }, mess);
        }
    };
} // namespace msg
 
#undef UNHANDLED_MSG_WARN
 
 
// main.cpp
#include <iostream>
 
#include "message.hpp"
 
namespace my
{
    struct A {};
 
    struct B {};
    
    struct C {};
 
    using Message = ::msg::Message<A, B, C>;
 
    class Test final
        : public ::msg::Handler<Message>
    {
        void onMessage(const B &) override { ::std::cout << "intercepted: B\n"; }
        void onMessage(const C &) override { ::std::cout << "intercepted: C\n"; }
    };
} // namespace my
 
int main()
{
    my::Test t;
    t.processMessage(my::A{});
    t.processMessage(my::B{});
    t.processMessage(my::C{});
}

Выхлоп clang:
warnings
Bash
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
prog.cc:18:14: warning: 'my::Test::onMessage' hides overloaded virtual function [-Woverloaded-virtual]
        void onMessage(const B &) override { ::std::cout << "intercepted: B\n"; }
             ^
./message.hpp:45:26: note: hidden overloaded virtual function 'msg::detail::HandlerImpl<my::A, my::B, my::C>::onMessage' declared here: type mismatch at 1st parameter ('const msg::detail::HandlerImpl<my::A, my::B, my::C>::MessageType &' (aka 'const my::A &') vs 'const my::B &')
            virtual void onMessage(const MessageType &) { UNHANDLED_MSG_WARN(MessageType) }
                         ^
prog.cc:19:14: warning: 'my::Test::onMessage' hides overloaded virtual function [-Woverloaded-virtual]
        void onMessage(const C &) override { ::std::cout << "intercepted: C\n"; }
             ^
./message.hpp:45:26: note: hidden overloaded virtual function 'msg::detail::HandlerImpl<my::A, my::B, my::C>::onMessage' declared here: type mismatch at 1st parameter ('const msg::detail::HandlerImpl<my::A, my::B, my::C>::MessageType &' (aka 'const my::A &') vs 'const my::C &')
            virtual void onMessage(const MessageType &) { UNHANDLED_MSG_WARN(MessageType) }
                         ^
./message.hpp:75:27: warning: lambda capture 'this' is not used [-Wunused-lambda-capture]
            ::std::visit([this](auto const & m){ onMessage(m); }, mess);
                          ^
prog.cc:26:7: note: in instantiation of member function 'msg::Handler<std::variant<my::A, my::B, my::C>>::processMessage' requested here
    t.processMessage(my::A{});
      ^
3 warnings generated.


Ссылка на онлайн-компилятор: https://wandbox.org/permlink/a0J8dAEWSmEHKB3c

GCC и VS при условно тех же настройках молчат.

Первые два про сокрытие имён мне понятны. И, в целом, я понимаю, как от них избавиться, просто вызывать виртуальные функции напрямую через наследников Handler не планируется, поэтому выносить их имена в скоуп наследников нет необходимости. Или я что-то упускаю и в коде зарыта мина?
А вот последнее предупреждение я вообще понять не могу, и как это исправить не представляю. Объясните, пожалуйста.

Не по теме:

Просто надоело редактировать код в куче разных мест, захотелось немного рефлексии. Понимаю, что криво, но по-другому не знаю как. Если подтолкнёте к правильному решению, тоже буду благодарен.

0
IT_Exp
Эксперт
34794 / 4073 / 2104
Регистрация: 17.06.2006
Сообщений: 32,602
Блог
27.01.2021, 21:16
Ответы с готовыми решениями:

Непонятное поведение компилятора
При запуске программы пишет build sucessful. При следующем запуске ничего не происходит: нету ни окна в области Build пусто, в процессах...

Предупреждение компилятора только в Release
Приветствую всех. Написал такой тестовый код: /*----- unit1.h -----*/ inline bool Foo(); /*----- unit1.cpp -----*/ bool...

Непонятное предупреждение. Ложное срабатывание?
Привет! Что именно не нравится компилятору? https://rextester.com/SZJI33812 class unexpected_warning { public: ...

9
6772 / 4565 / 1844
Регистрация: 07.05.2019
Сообщений: 13,726
27.01.2021, 21:32
Лучший ответ Сообщение было отмечено zayats80888 как решение

Решение

Цитата Сообщение от zayats80888 Посмотреть сообщение
А вот последнее предупреждение я вообще понять не могу, и как это исправить не представляю. Объясните, пожалуйста.
Попробуй убрать using Base::onMessage и сделать в лямбде this->onMessage(m)
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
 template <class Message>
    class Handler
        : private detail::HandlerBase<Message>::Type
    {
        using Base = typename detail::HandlerBase<Message>::Type;
        ////using Base::onMessage;
    public:
 
        virtual ~Handler() = default;
    
        void processMessage(const Message & mess)
        {
            ::std::visit([this](auto const & m) { this->onMessage(m); }, mess);
        }
    };
Добавлено через 7 минут
C++
1
2
3
4
5
6
7
8
9
10
11
12
template <class T>
struct HandlerImpl<T>
{
    using MessageType = T;
            
    virtual void onMessage(const MessageType &) { UNHANDLED_MSG_WARN(MessageType) }
};
        
template <class T, class ... Ts>
struct HandlerImpl<T, Ts...> : HandlerImpl<T>, HandlerImpl<Ts...>
{
};
1
 Аватар для eva2326
1673 / 501 / 107
Регистрация: 17.05.2015
Сообщений: 1,518
28.01.2021, 00:12
Лучший ответ Сообщение было отмечено zayats80888 как решение

Решение

Цитата Сообщение от zayats80888 Посмотреть сообщение
Прошу объяснить проедупреждение, которое генерирует Clang для этого кода:
Он же нормальным английским языком пишет: методы наследника скрывают одноименные методы базового класса.

Предупреждение, кстати, справедливое.
Согласно вашей задумке, вы же должны иметь возможность запустить unhandled message: my::A через наследника?

А значит, по хорошему, нужно отреагировать на сигнал от компилятора, и немножко исправить код:

https://wandbox.org/permlink/UVply9ZKkEhn0lVg

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
// main.cpp
 
#include <iostream>
#include "message.hpp"
 
namespace my
{
    struct A {};
    struct B {};
    struct C {};
    using Message = ::msg::Message<A, B, C>;
 
    class Test final : public ::msg::Handler<Message>
    {
        using Base = ::msg::Handler<Message>;
        using Base::onMessage;
        void onMessage(const B &) override { ::std::cout << "intercepted: B\n"; }
        void onMessage(const C &) override { ::std::cout << "intercepted: C\n"; }
    };
} // namespace my
 
int main()
{
    my::Test t;
    t.processMessage(my::A{});
    t.processMessage(my::B{});
    t.processMessage(my::C{});
}
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
// message.hpp
 
#pragma once
 
#include <utility>
#include <variant>
 
#ifdef UNHANDLED_MSG_WARN
    #error "UNHANDLED_MSG_WARN macro conflict"
#endif
 
#if defined(DEBUG) || defined(_DEBUG)
    #include <iostream>
    #include <typeinfo>
    #include <boost/core/demangle.hpp>
    #define UNHANDLED_MSG_WARN(T) \
        ::std::cout << "unhandled message: " \
                    << ::boost::core::demangle(typeid(T).name()) \
                    << '\n';
#else
    #define UNHANDLED_MSG_WARN(T)
#endif
 
namespace msg
{
    namespace detail
    {
        template <class ... Ts>
        struct HandlerImpl;
        
        template <class T>
        struct HandlerImpl<T>
        {
            using MessageType = T;
            
            virtual void onMessage(const MessageType &) { UNHANDLED_MSG_WARN(MessageType) }
        };
        
        template <class T, class ... Ts>
        struct HandlerImpl<T, Ts...> : HandlerImpl<Ts...>
        {
            using MessageType = T;
            using Base = HandlerImpl<Ts...>;
            
            using Base::onMessage;
            
            virtual void onMessage(const MessageType &) { UNHANDLED_MSG_WARN(MessageType) }
        };
        
               
        template <template <class...> class Variant, class ... Ts>
        HandlerImpl<Ts...> hanlerTypes(Variant<Ts...> &&);
        
        template <class Variant,
                  class T = decltype(hanlerTypes(::std::declval<Variant>()))>
        struct HandlerBase
        {
           using Type = T;
        };
    } // namespace detail
    
    template <class ... Ts>
    using Message = ::std::variant<Ts...>;
    
    template <class Message>
    class Handler
        : private detail::HandlerBase<Message>::Type
    {
        using Base = typename detail::HandlerBase<Message>::Type;
    protected:
        using Base::onMessage;
    public:
 
        virtual ~Handler() = default;
    
        void processMessage(const Message & mess)
        {
            ::std::visit([this](auto const & m){ this->onMessage(m); }, mess);
        }
    };
} // namespace msg
 
#undef UNHANDLED_MSG_WARN
1
 Аватар для zayats80888
6352 / 3523 / 1428
Регистрация: 07.02.2019
Сообщений: 8,995
28.01.2021, 00:31  [ТС]
Цитата Сообщение от oleg-m1973 Посмотреть сообщение
сделать в лямбде this->onMessage(m)
Ок, это убирает предупреждение. Только почему оно появилось, я так и не понял...
Цитата Сообщение от oleg-m1973 Посмотреть сообщение
template <class T, class ... Ts>
struct HandlerImpl<T, Ts...> : HandlerImpl<T>, HandlerImpl<Ts...>
А это для чего? Множественное наследование тут не прокатит.

Цитата Сообщение от eva2326 Посмотреть сообщение
Он же нормальным английским языком пишет:
Я написал, что я его понимаю.
Цитата Сообщение от eva2326 Посмотреть сообщение
Предупреждение, кстати, справедливое.
Согласен, поэтому и спросил, не упускаю ли я что.

Цитата Сообщение от eva2326 Посмотреть сообщение
Согласно вашей задумке, вы же должны иметь возможность запустить unhandled message: my::A через наследника?
А вот это я не понял. Я написал, что через наследников вообще ничего вызываться не будет.
И даже в примере, несмотря на то, что вызываем через Test, мы вызываем метод предка(не виртуальный, который и перенаправляет на виртуальный). Или я что-то не так понял?
0
6772 / 4565 / 1844
Регистрация: 07.05.2019
Сообщений: 13,726
28.01.2021, 00:37
Цитата Сообщение от zayats80888 Посмотреть сообщение
А это для чего? Множественное наследование тут не прокатит.
В смысле, не прокатит? Прокатит. И довольно сильно уменьшит код.

Добавлено через 2 минуты
Здесь вообще не нужно делать рекурсивное наследование
C++
1
2
3
4
5
6
7
8
9
10
11
12
template <class T>
struct _HandlerImpl<T>
{
    using MessageType = T;
            
    virtual void onMessage(const MessageType &) { UNHANDLED_MSG_WARN(MessageType) }
};
        
template <class ... Ts>
struct HandlerImpl<Ts...> : _HandlerImpl<Ts>...
{
};
0
 Аватар для zayats80888
6352 / 3523 / 1428
Регистрация: 07.02.2019
Сообщений: 8,995
28.01.2021, 00:41  [ТС]
Цитата Сообщение от oleg-m1973 Посмотреть сообщение
Прокатит.
Как же прокатит? Там при name lookup будет неоднозначность. У вас это компилируется?
0
6772 / 4565 / 1844
Регистрация: 07.05.2019
Сообщений: 13,726
28.01.2021, 00:54
Цитата Сообщение от zayats80888 Посмотреть сообщение
Как же прокатит? Там при name lookup будет неоднозначность. У вас это компилируется?
Ну да, не компилируется
0
 Аватар для zayats80888
6352 / 3523 / 1428
Регистрация: 07.02.2019
Сообщений: 8,995
28.01.2021, 12:36  [ТС]
Цитата Сообщение от zayats80888 Посмотреть сообщение
Только почему оно появилось, я так и не понял...
Есть предположение, что это предупреждение генерируется во время предварительного лукапа, потому что Base::onMessage - зависимое имя и компилятор его не соотносит с this. А потом просто его не "убирает". Но это не точно...

Добавлено через 1 час 17 минут

Не по теме:

Цитата Сообщение от oleg-m1973 Посмотреть сообщение
Ну да, не компилируется
Кстати, эту неоднозначность можно решить так:
C++
1
2
3
4
5
        template <class ... Ts>
        struct HandlerImpl : _HandlerImpl<Ts>...
        {
            using _HandlerImpl<Ts>::onMessage...;
        };

0
6772 / 4565 / 1844
Регистрация: 07.05.2019
Сообщений: 13,726
28.01.2021, 12:40
Цитата Сообщение от zayats80888 Посмотреть сообщение
Кстати, эту неоднозначность можно решить так:
Возможно. Я просто не стал вчера заморачиваться. Но, если работает, то выглядит явно лучше, чем первоначальный код.
0
 Аватар для eva2326
1673 / 501 / 107
Регистрация: 17.05.2015
Сообщений: 1,518
28.01.2021, 12:54
Цитата Сообщение от zayats80888 Посмотреть сообщение
А вот это я не понял. Я написал, что через наследников вообще ничего вызываться не будет.
И даже в примере, несмотря на то, что вызываем через Test, мы вызываем метод предка(не виртуальный, который и перенаправляет на виртуальный). Или я что-то не так понял?
Вы всё правильно поняли.
Однако ваша ситуация - тот забавный случай, когда на высказывание:
Цитата Сообщение от zayats80888 Посмотреть сообщение
вызывать виртуальные функции напрямую через наследников Handler не планируется
Правильный ответ: "Планируется. Просто вы об том пока ещё не знаете".

Архитектурно у вас сейчас:
- Библиотечный код, который реализует доставку сообщения.
- Пользовательский наследник, который реализует обработку различных сообщений.


Если вы в своей библиотеке не откроете наследникам доступ:
Цитата Сообщение от eva2326 Посмотреть сообщение
protected:
        using Base::onMessage;
Тогда в пользовательском коде (в наследниках) уже нельзя будет использовать:
Цитата Сообщение от eva2326 Посмотреть сообщение
using Base::onMessage;
То есть, ваша блиотека в принципе ограничит кейсы наследников.
На каком основании?


Вы испольнуете полиморфизм тогда, когда вам нужно переопределять поведение.
Если по вашей задумке, у вас там строго одно определенное поведение, то вам не нужен полиморфизм.
Но если уж вы его использовали - значит предполагается, что поведения могут быть разными.

То, что у вас сейчас на на примете только один единственный наследник, не даёт вам оснований ограничивать всю архитектуру одним единственным поведенческим кейсом.

Моя первая реакция:
Цитата Сообщение от eva2326 Посмотреть сообщение
вы же должны иметь возможность запустить unhandled message: my::A через наследника?
Было бы очень странно, если бы было иначе.
Речь не о конкретном наследнике Test, а о наследниках вообще.
Зачем проектировать такую архитектуру, которая на ровном месте исскуственно вводит ограничения, в результате которых нельзя будет конструировать полноценных наследников?

Вы успешно отработаете своей единственный кейс, а дальше ваша библиотека пойдёт в мусорное ведро, потому что с такими дурацкими ограничениями, она непригодна для полноценного использования.

Компилятор сделал предупреждение, потому что он решил, что вы ничайно забыли расшарить видимость методов предков, потому что иначе получается бред.
1
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
BasicMan
Эксперт
29316 / 5623 / 2384
Регистрация: 17.02.2009
Сообщений: 30,364
Блог
28.01.2021, 12:54
Помогаю со студенческими работами здесь

Предупреждение компилятора применение устаревших библиотек
И снова к Вам за мудрым советом, люди которые делают наш мир интересней! Други, есть код, при запуске пишет &quot;Предупреждение...

[c++] gcc, почему не подавляется предупреждение компилятора?
Привет! Почему не подавляется предупреждение? https://rextester.com/HWHJ72731 #include &lt;iostream&gt; #include...

Предупреждение компилятора "integer overflow in expression"
#include &lt;iostream&gt; #include &lt;conio.h&gt; using namespace std; int main() { int a, b; double c;

Предупреждение компилятора "J' is assigned a value that is never used"
Здравствуйте. В университете только начали изучать эту программу. И домой задали написать одну функцию. Точнее вот эту r=(d+b)/c. Где...

Ошибка компилятора fatal error C1091: ограничение компилятора: длина строки превышает 65535 байт
Компилируя программу вот такой командой: cl /O2 /Oi /GL /EHsc /MD /Gy main.cpp И компилятор выдает вот такую ошибку: ...


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

Или воспользуйтесь поиском по форуму:
10
Ответ Создать тему
Новые блоги и статьи
http://iceja.net/ сервер решения полиномов
iceja 18.01.2026
Выкатила http:/ / iceja. net/ сервер решения полиномов (находит действительные корни полиномов методом Штурма). На сайте документация по API, но скажу прямо VPS слабенький и 200 000 полиномов. . .
Первый деплой
lagorue 16.01.2026
Не спеша развернул своё 1ое приложение в kubernetes. А дальше мне интересно создать 1фронтэнд приложения и 2 бэкэнд приложения развернуть 2 деплоя в кубере получится 2 сервиса и что-бы они. . .
Расчёт переходных процессов в цепи постоянного тока
igorrr37 16.01.2026
/ * Дана цепь постоянного тока с R, L, C, k(ключ), U, E, J. Программа составляет систему уравнений по 1 и 2 законам Кирхгофа, решает её и находит: токи, напряжения и их 1 и 2 производные при t = 0;. . .
Восстановить юзерскрипты Greasemonkey из бэкапа браузера
damix 15.01.2026
Если восстановить из бэкапа профиль Firefox после переустановки винды, то список юзерскриптов в Greasemonkey будет пустым. Но восстановить их можно так. Для этого понадобится консольная утилита. . .
Изучаю 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. Программа предоставляет более. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru