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

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

27.01.2021, 21:16. Показов 3462. Ответов 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,519
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,519
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
Ответ Создать тему
Новые блоги и статьи
модель ЗдравоСохранения 8. Подготовка к разному выполнению заданий
anaschu 08.04.2026
https:/ / github. com/ shumilovas/ med2. git main ветка * содержимое блока дэлэй из старой модели теперь внутри зайца новой модели 8ATzM_2aurI
Блокировка документа от изменений, если он открыт у другого пользователя
Maks 08.04.2026
Алгоритм из решения ниже реализован на примере нетипового документа, разработанного в конфигурации КА2. Задача: запретить редактирование документа, если он открыт у другого пользователя. / / . . .
Система безопасности+живучести для сервера-слоя интернета (сети). Двойная привязка.
Hrethgir 08.04.2026
Далее были размышления о системе безопасности. Сообщения с наклонным текстом - мои. А как нам будет можно проверить, что ссылка наша, а не подделана хулиганами, которая выбросит на другую ветку и. . .
Модель ЗдрввоСохранения 7: больше работников, больше ресурсов.
anaschu 08.04.2026
работников и заданий может быть сколько угодно, но настроено всё так, что используется пока что только 20% kYBz3eJf3jQ
Дальние перспективы сервера - слоя сети с космологическим дизайном интефейса карты и логики.
Hrethgir 07.04.2026
Дальнейшее ближайшее планирование вывело к размышлениям над дальними перспективами. И вот тут может быть даже будут нужны оценки специалистов, так как в дальних перспективах всё может очень сильно. . .
Горе от ума
kumehtar 07.04.2026
Эта мне ментальная установка, что вот прямо сейчас, мол, мне для полного счастья не хватает (нужное вписать), и когда я этого достигну - тогда и полный кайф. Одна из самых сильных ловушек на пути. . . .
Использование значений реквизитов справочника в документе, с определенными условиями и правами
Maks 07.04.2026
1. Контроль срока действия договора Алгоритм из решения ниже реализован на примере нетипового документа "ЗаявкаНаРаботу", разработанного в конфигурации КА2. Задача: уведомлять пользователя, если. . .
Доступность команды формы по условию
Maks 07.04.2026
Алгоритм из решения ниже реализован на примере нетипового документа "СписаниеМатериалов", разработанного в конфигурации КА2. Задача: сделать доступной кнопку (команда формы "ЗавершитьСписание") при. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru