V>Хочется спросить у знатоков С++ — что происходит с перегрузкой, почему так и по стандарту ли это? Можно как-то поправить (сделать что бы operator& разрешался только для класса A<uint_t>) ?
Так он и разрешается только для воплощений шаблонного класса A. А для перечислений En не разрешается, поэтому и возникает ошибка компиляции. Я полагаю, это очевидно и без ссылок на конкретные пункты стандарта, не так ли? А вот как должно выглядеть диагностическое сообщение об ошибке — этого в стандарте, конечно же нет, оно может иметь различную форму у разных компиляторов. Понятно, что разработчики компиляторов стараются сделать сделать свои диагностические сообщения максимально полезными и понятными. Ну а получается уже как получается.
Здравствуйте, Videoman, Вы писали:
σ>>А в чём проблема? VC просто сообщает, что не смог использовать ни встроенный оператор &, ни шаблонный. V>Т.е. это такое завуалированное сообщение о том что не найден оператор для En ? Если у меня будет еще куча перегрузок, то он их все выведет?
Это такие кривые сообщения об ошибках у компилятора студии
[In theory there is no difference between theory and practice. In
practice there is.]
[Даю очевидные ответы на риторические вопросы]
Здравствуйте, rg45, Вы писали:
R>Так он и разрешается только для воплощений шаблонного класса A. А для перечислений En не разрешается, поэтому и возникает ошибка компиляции. Я полагаю, это очевидно и без ссылок на конкретные пункты стандарта, не так ли? А вот как должно выглядеть диагностическое сообщение об ошибке — этого в стандарте, конечно же нет, оно может иметь различную форму у разных компиляторов. Понятно, что разработчики компиляторов стараются сделать сделать свои диагностические сообщения максимально полезными и понятными. Ну а получается уже как получается.
Не совсем. Вот тут я попытался обозначить проблему. Оператор& класса A<size> маскирует оператор& Enum-а. Если его убрать, то все ок.
#include <iostream>
using namespace std;
namespace impl
{
template<typename Enum, class = decltype(enable_bitmask_operators(*(Enum*)nullptr))>
inline Enum operator&(Enum left, Enum right)
{
using Underlying = std::underlying_type_t<Enum>;
return static_cast<Enum>(static_cast<Underlying>(left) & static_cast<Underlying>(right));
}
}
namespace my
{
using namespace impl;
enum class Enum : int { a, b, c };
void enable_bitmask_operators(Enum);
template<int size>
class A
{
};
//template<int size> // Если это раскомментраить то то перестает компилироваться
//A<size> operator&(const A<size>&, const A<size>&); // Если это раскомментраить то то перестает компилироватьсяvoid func()
{
Enum en1 = Enum::a;
Enum en2 = Enum::b;
Enum en3 = Enum::a & Enum::b;
}
} // namespace mynamespace my2
{
using namespace impl;
my::Enum en3 = my::Enum::a & my::Enum::b;
} // namespace my2int main()
{
return 0;
}
Здравствуйте, Videoman, Вы писали: R>>Так он и разрешается только для воплощений шаблонного класса A. А для перечислений En не разрешается, поэтому и возникает ошибка компиляции. Я полагаю, это очевидно и без ссылок на конкретные пункты стандарта, не так ли? А вот как должно выглядеть диагностическое сообщение об ошибке — этого в стандарте, конечно же нет, оно может иметь различную форму у разных компиляторов. Понятно, что разработчики компиляторов стараются сделать сделать свои диагностические сообщения максимально полезными и понятными. Ну а получается уже как получается. V>Не совсем. Вот тут я попытался обозначить проблему. Оператор& класса A<size> маскирует оператор& Enum-а. Если его убрать, то все ок. V>
ccode
V>
V>#include <iostream>
V>using namespace std;
V>namespace impl
V>{
V> template<typename Enum, class = decltype(enable_bitmask_operators(*(Enum*)nullptr))>
V> inline Enum operator&(Enum left, Enum right)
V> {
V> using Underlying = std::underlying_type_t<Enum>;
V> return static_cast<Enum>(static_cast<Underlying>(left) & static_cast<Underlying>(right));
V> }
V>}
V>namespace my
V>{
V>using namespace impl;
V>enum class Enum : int { a, b, c };
V>void enable_bitmask_operators(Enum);
V>template<int size>
V>class A
V>{
V>};
V>//template<int size> // Если это раскомментраить то то перестает компилироваться
V>//A<size> operator&(const A<size>&, const A<size>&); // Если это раскомментраить то то перестает компилироваться
V>void func()
V>{
V> Enum en1 = Enum::a;
V> Enum en2 = Enum::b;
V> Enum en3 = Enum::a & Enum::b;
V>}
V>} // namespace my
V>namespace my2
V>{
V> using namespace impl;
V> my::Enum en3 = my::Enum::a & my::Enum::b;
V>} // namespace my2
V>int main()
V>{
V> return 0;
V>}
V>
. Используй using-declaration вместо using-directive: R>
R> using impl::operator&;
R>
Действительно работает, спасибо большое . Тогда, для общего развития, можно пояснить два вопроса:
1. Чем эта декларация отличается от using namespace impl ?
2. using impl::operator&; — "втягивает" объявление осех операторов& ?
V>Действительно работает, спасибо большое . Тогда, для общего развития, можно пояснить два вопроса: V>1. Чем эта декларация отличается от using namespace impl ?
Это в стандарте есть, назвается argument dependent name lookup (ADL), кажется. Там перечислятеся в каких пространствах имен ищутся кандитаы на подстановку. В данном случае ADL сначала заглядывает в пространство имен, в котором определено перечисление En. Там искомый оператор не находится. Тогда поиск начинается от того пространства имен, в котором содержится обращение к оператору и выше, к обрамляющим пространствам имен, а также в пространсвах имен, которые включены при помощи using-directives. Это восхожение прекращается, как только искомое имя (operator&) находится. Тогда начинается анализ всех доступных в этом пространстве кандидатов на подстановку. В данном случае ADL натыкается на operator& для воплощений шаблонного класса A и в пространство impl уже не идет. В случае же использования using-declaration&, operator& из пространства имен impl оказывается внесенным в пространство имен my и находится как самый подходяший кандидат на подстановку.
V>2. using impl::operator&; — "втягивает" объявление осех операторов& ?