явная специализация для оператора перегрузки ‘& lt; & lt;’ (Сдвиг влево)

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

#include <iostream>

enum class option : char { normal, do_something_stupid };

class foo
{
public:

int i;
explicit foo(int a=0) : i(a) {};
/* overload operator '+=' based on 'option' */
template<option E = option::normal>
void operator+=(const foo& f) { i += f.i; }
};

/* explicit specialization for operator += */
template<> void foo::operator+=<option::do_something_stupid>(const foo& f)
{ i += (f.i +1000); }

int main()
{
foo f1(1), f2(2);
f1 += f2;
std::cout << "\nf1 = " << f1.i;
f1.operator+=<option::do_something_stupid>(f2);
std::cout << "\nf1 = " << f1.i;

std::cout << "\n";
return 0;
}

Это создает чистоту (игнорируя тот факт, что он действительно делает что-то симпатичное) как на g ++, так и на clang ++.

Что делать, если я хочу перегрузить<<оператор так же? Похожий подход не работает:

#include <ostream>
#include <iostream>

enum class option : char { normal, do_something_stupid };

class foo
{
public:

int i;

explicit foo(int a=0) : i(a) {};

template<option E = option::normal>
friend std::ostream& operator<<(std::ostream& o, const foo& f)
{ o << f.i; return o; }
};

template<> std::ostream&
operator<< <option::do_something_stupid>(std::ostream& o, const foo& f)
{
o << f.i + 1000;
return o;
}

int main()
{
foo f1(1), f2(2);

std::cout << "\nf1= " << f1;
std::cout << "\nf2= ";
/* this triggers an error with g++ */
std::cout.operator<< <option::do_something_stupid>(f1);

std::cout << "\n";
return 0;
}

Согласно g ++, вызов от main к оператору недопустим:

error: no match for ‘operator<’ (operand types are ‘<unresolved overloaded function type>’ and ‘option’)
std::cout.operator<< <option::do_something_stupid>(f1);

clang ++, с другой стороны, выдает другое сообщение об ошибке:

lsfov.cc:20:1: error: 'operator<<' cannot be the name of a variable or data member
operator<< <option::do_something_stupid>(std::ostream& o, const foo& f)
^
lsfov.cc:20:11: error: expected ';' at end of declaration
operator<< <option::do_something_stupid>(std::ostream& o, const foo& f)
^
;
lsfov.cc:20:12: error: expected unqualified-id
operator<< <option::do_something_stupid>(std::ostream& o, const foo& f)
^
lsfov.cc:33:15: error: reference to non-static member function must be called
std::cout.operator<< <option::do_something_stupid>(f1);
~~~~~~~~~~^~~~~~~~~~

который идет на листинг возможной перегрузки ‘<<‘из стандартной библиотеки (если я правильно понимаю), например:

/usr/bin/../lib/gcc/x86_64-redhat-linux/5.3.1/../../../../include/c++/5.3.1/ostream:108:7: note: possible target for call
operator<<(__ostream_type& (*__pf)(__ostream_type&))
^
/usr/bin/../lib/gcc/x86_64-redhat-linux/5.3.1/../../../../include/c++/5.3.1/ostream:117:7: note: possible target for call
operator<<(__ios_type& (*__pf)(__ios_type&))
^

Что здесь происходит? Возможна ли / разрешена ли такая специализация оператора? Если да, то как правильно позвонить оператору? Или же лязг верен и определение плохо сформировано?

1

Решение

Я думаю, что Clang не нравится декларация friend по отношению к специализации. Переупорядочение их делает свое дело.

enum class option : char { normal, do_something_stupid };

// forward declare the class and operator
class foo;

template<option E = option::normal>
std::ostream& operator<<(std::ostream& o, const foo& f);

// the class with the declared friend operator
class foo
{
private:
int i;
public:
explicit foo(int a=0) : i(a) {};
template<option E>
friend std::ostream& operator<<(std::ostream& o, const foo& f);
};

// the operator implementations
template<option E>
std::ostream& operator<<(std::ostream& o, const foo& f)
{ o << f.i; return o; }

template<> std::ostream&
operator<< <option::do_something_stupid>(std::ostream& o, const foo& f)
{
o << f.i + 1000;
return o;
}

В дополнение operator<< используется в main не является членом coutСкорее глобальный.

int main()
{
foo f1(1), f2(2);

std::cout << "\nf1= " << f1;
std::cout << "\nf2= ";
/* this triggers an error with g++ */
operator<< <option::do_something_stupid>(std::cout, f1);

std::cout << "\n";
return 0;
}

Образец здесь. g ++ также доволен кодом, описанным выше.


Замечание об операторах в не выводимом контексте. Я предполагаю, что вы используете код здесь в каком-то большем проекте, но если оператор используется с необработанными параметрами, часто проще и понятнее реализовать функциональность в методе-члене или свободной функции (используя friend как требуется).

2

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]