重载运算符 '<<' 的显式特化(左移)
explicit specialization for overloading operator '<<' (left shift)
假设我有一个 class,我想为其重载一个基于枚举类型的运算符:
#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到operator的调用是无效的:
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&))
^
这是怎么回事?这种运算符特化possible/allowed?如果是这样,打电话给接线员的正确方法是什么?或者 clang 是否正确并且定义格式不正确?
我认为 clang 不喜欢 friend
关于专业化的声明。 Re-ordering 他们成功了。
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;
}
另外,在main
中使用的operator<<
不是成员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;
}
Sample here。 g++ 也对上面的代码感到满意。
关于 non-deduced 上下文中运算符的说明。我假设您在某种更大的项目中使用此处的代码,但如果运算符与 non-deduced 参数一起使用,则通常更容易和更清晰地在成员方法或自由函数中实现功能(根据需要使用 friend
)。
假设我有一个 class,我想为其重载一个基于枚举类型的运算符:
#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到operator的调用是无效的:
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&))
^
这是怎么回事?这种运算符特化possible/allowed?如果是这样,打电话给接线员的正确方法是什么?或者 clang 是否正确并且定义格式不正确?
我认为 clang 不喜欢 friend
关于专业化的声明。 Re-ordering 他们成功了。
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;
}
另外,在main
中使用的operator<<
不是成员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;
}
Sample here。 g++ 也对上面的代码感到满意。
关于 non-deduced 上下文中运算符的说明。我假设您在某种更大的项目中使用此处的代码,但如果运算符与 non-deduced 参数一起使用,则通常更容易和更清晰地在成员方法或自由函数中实现功能(根据需要使用 friend
)。