在之前的项目中,我遇到了类似的错误,因此我决定从新方法开始,并且仍然遇到同样的问题。我有一个键值对模板类,除流操作符外,一切正常。我有<<
的模板接受kvp_node<key, elem> &kvp
或kvp_node<key, elem> *kvp
。我能够创建kvp_node
个对象并使用它们的成员函数,没有任何问题。但如果我尝试做类似的事情:
kvp_node<char, int> test('A', 10);
std::cout << test;
它为我提供了未解决的外部操作员错误。 我觉得好像我已正确定义了我的流操作符。如果我试着这样做:
kvp_node<char, int> name('J', 12);
std::cout << name.elm_();
它没有错误,这就是为什么这会让人感到困惑,因为所有的ostream运算符都是
os << (kvp_node<key, elem> test(key, elem)).elm_()
这是我的头文件:
#ifndef DICT_H_
#define DICT_H_
#include<iostream>
#include<fstream>
//Stores Key Value pairs in a linked node can be used
//to implement various KV based ADTs
//kvp_nodes can be compared using normal comparator
//operations. These operations will use the comparators
//for the key class type, so if the key class is a user
//defined type, they must define the comparators for the
//class
template<typename key, typename elem>
class kvp_node {
bool setinel;
key k_val;
elem e_val;
kvp_node<key, elem> *next;
kvp_node<key, elem> *prev;
public:
//default constructor
kvp_node();
//use this constructor
kvp_node(key k, elem e, bool set = false);
//destructor
~kvp_node();
//copy constructor
kvp_node(const kvp_node<key, elem> &kvp);
//assignment constructor
void operator=(const kvp_node<key, elem> &kvp_);
//returns keyvalue
key key_();
//returns element
elem elm_();
//sets key value
void set_key(key k);
//sets element value
void set_elm(elem e);
//comparators, all will use the default comparators for the key type
bool operator==(kvp_node<key, elem> &kvp);
bool operator>=(kvp_node<key, elem> &kvp);
bool operator<=(kvp_node<key, elem> &kvp);
bool operator>(kvp_node<key, elem> &kvp);
bool operator<(kvp_node<key, elem> &kvp);
//returns next node
kvp_node<key, elem> *gnext();
//returns previous node
kvp_node<key, elem> *gprev();
//node linking functions
//sets the next node
void set_next(kvp_node<key, elem> *kvp);
//sets the previous node
void set_prev(kvp_node<key, elem> *kvp);
//links node a forward to b and b backward to a
void link_nodes(kvp_node<key, elem> *A, kvp_node<key, elem> *B);
//setinel functions
//makes setinel
void set_set();
//returns setinel value
bool set();
//standard io stream operators
//ostream <<
friend std::ostream& operator<<(std::ostream &os, kvp_node<key, elem> &kvp);
friend std::ostream& operator<<(std::ostream &os, kvp_node<key, elem> *kvp);
//istream
//add later
//standard file stream operators
//ofstream <<
friend std::ofstream& operator<<(std::ofstream &fo, kvp_node<key, elem> &kvp);
friend std::ofstream& operator<<(std::ofstream &fo, kvp_node<key, elem> *kvp);
//ifstream
//add later
};
//constructors, destructors, assignment
template<typename key, typename elem>
kvp_node<key, elem>::kvp_node() {
}
template<typename key, typename elem>
kvp_node<key, elem>::kvp_node(key k, elem e, bool set) {
k_val = k;
e_val = e;
setinel = set;
}
template<typename key, typename elem>
kvp_node<key, elem>::~kvp_node(){
}
template<typename key, typename elem>
kvp_node<key, elem>::kvp_node(const kvp_node<key, elem> &kvp) {
k_val = kvp.key_();
e_val = kvp.elm_();
setinel = kvp.set();
}
template<typename key, typename elem>
void kvp_node<key, elem>::operator=(const kvp_node<key, elem> &kvp) {
k_val = kvp.key_();
e_val = kvp.elm_();
setinel = kvp.set();
}
// ==================================
//get object values
template<typename key, typename elem>
key kvp_node<key, elem>::key_() {
return k_val;
}
template<typename key, typename elem>
elem kvp_node<key, elem>::elm_() {
return e_val;
}
template<typename key, typename elem>
bool kvp_node<key, elem>::set() {
return setinel;
}
// ==================================
//set object values
template<typename key, typename elem>
void kvp_node<key, elem>::set_key(key k) {
k_val = k;
}
template<typename key, typename elem>
void kvp_node<key, elem>::set_elm(elem e) {
e_val = e;
}
template<typename key, typename elem>
void kvp_node<key, elem>::set_set() {
setinel = true;
}
// =================================
//get neighbor kv pair nodes
template<typename key, typename elem>
kvp_node<key, elem> *kvp_node<key, elem>::gnext() {
return next;
}
template<typename key, typename elem>
kvp_node<key, elem> *kvp_node<key, elem>::gprev() {
return prev;
}
// =================================
//set neighbor kv pair nodes
template<typename key, typename elem>
void kvp_node<key, elem>::set_next(kvp_node<key, elem> *kvp) {
next = kvp;
}
template<typename key, typename elem>
void kvp_node<key, elem>::set_prev(kvp_node<key, elem> *kvp) {
prev = kvp;
}
template<typename key, typename elem>
void kvp_node<key, elem>::link_nodes(kvp_node<key, elem> *A, kvp_node<key, elem> *B) {
A->set_next(B);
B->set_prev(A);
}
// ==================================
//comparison operators
template<typename key, typename elem>
bool kvp_node<key, elem>::operator<(kvp_node<key, elem> &kvp) {
return (k_val < kvp.key_()) ? (true) : (false);
}
template<typename key, typename elem>
bool kvp_node<key, elem>::operator>(kvp_node<key, elem> &kvp) {
return (k_val > kvp.key_()) ? (true) : (false);
}
template<typename key, typename elem>
bool kvp_node<key, elem>::operator<=(kvp_node<key, elem> &kvp) {
return (k_val <= kvp.key_()) ? (true) : (false);
}
template<typename key, typename elem>
bool kvp_node<key, elem>::operator>=(kvp_node<key, elem> &kvp) {
return (k_val >= kvp.key_()) ? (true) : (false);
}
template<typename key, typename elem>
bool kvp_node<key, elem>::operator==(kvp_node<key, elem> &kvp) {
return (k_val == kvp.key_()) ? (true) : (false);
}
// ==================================
//stream operators
template<typename key, typename elem>
std::ostream &operator<<(std::ostream &os, kvp_node<key, elem> &kvp) {
os << kvp.elm_();
return os;
}
template<typename key,typename elem>
std::ostream &operator<<(std::ostream &os, kvp_node<key, elem> *kvp) {
os << kvp->elm_();
return os;
}
#endif
我如何使用所有其他类成员但流操作符不起作用?
答案 0 :(得分:1)
我得到了它的工作。这是我的变化。 (我对提交内容进行了调整,所以在我修改格式时请原谅我。)
代码
#include<iostream>
#include<fstream>
//Stores Key Value pairs in a linked node can be used
//to implement various KV based ADTs
//kvp_nodes can be compared using normal comparator
//operations. These operations will use the comparators
//for the key class type, so if the key class is a user
//defined type, they must define the comparators for the
//class
template<typename key, typename elem>
class kvp_node {
bool setinel;
key k_val;
elem e_val;
kvp_node<key, elem> *next;
kvp_node<key, elem> *prev;
public:
//default constructor
kvp_node();
//use this constructor
kvp_node(key k, elem e, bool set = false);
//destructor
~kvp_node();
//copy constructor
kvp_node(const kvp_node<key, elem> &kvp);
//assignment constructor
void operator=(const kvp_node<key, elem> &kvp_);
//returns keyvalue
key key_()const;
//returns element
elem elm_()const;
//sets key value
void set_key(key k);
//sets element value
void set_elm(elem e);
//comparators, all will use the default comparators for the key type
bool operator==(kvp_node<key, elem> &kvp)const;
bool operator>=(kvp_node<key, elem> &kvp)const;
bool operator<=(kvp_node<key, elem> &kvp)const;
bool operator>(kvp_node<key, elem> &kvp)const;
bool operator<(kvp_node<key, elem> &kvp)const;
//returns next node
kvp_node<key, elem> *gnext();
//returns previous node
kvp_node<key, elem> *gprev();
//node linking functions
//sets the next node
void set_next(kvp_node<key, elem> *kvp);
//sets the previous node
void set_prev(kvp_node<key, elem> *kvp);
//links node a forward to b and b backward to a
void link_nodes(kvp_node<key, elem> *A, kvp_node<key, elem> *B);
//setinel functions
//makes setinel
void set_set();
//returns setinel value
bool set()const;
};
//constructors, destructors, assignment
template<typename key, typename elem>
kvp_node<key, elem>::kvp_node() {
}
template<typename key, typename elem>
kvp_node<key, elem>::kvp_node(key k, elem e, bool set) {
k_val = k;
e_val = e;
setinel = set;
}
template<typename key, typename elem>
kvp_node<key, elem>::~kvp_node(){
}
template<typename key, typename elem>
kvp_node<key, elem>::kvp_node(const kvp_node<key, elem> &kvp) {
k_val = kvp.key_();
e_val = kvp.elm_();
setinel = kvp.set();
}
template<typename key, typename elem>
void kvp_node<key, elem>::operator=(const kvp_node<key, elem> &kvp) {
k_val = kvp.key_();
e_val = kvp.elm_();
setinel = kvp.set();
}
// ==================================
//get object values
template<typename key, typename elem>
key kvp_node<key, elem>::key_()const{
return k_val;
}
template<typename key, typename elem>
elem kvp_node<key, elem>::elm_()const{
return e_val;
}
template<typename key, typename elem>
bool kvp_node<key, elem>::set()const{
return setinel;
}
// ==================================
//set object values
template<typename key, typename elem>
void kvp_node<key, elem>::set_key(key k) {
k_val = k;
}
template<typename key, typename elem>
void kvp_node<key, elem>::set_elm(elem e) {
e_val = e;
}
template<typename key, typename elem>
void kvp_node<key, elem>::set_set() {
setinel = true;
}
// =================================
//get neighbor kv pair nodes
template<typename key, typename elem>
kvp_node<key, elem> *kvp_node<key, elem>::gnext() {
return next;
}
template<typename key, typename elem>
kvp_node<key, elem> *kvp_node<key, elem>::gprev() {
return prev;
}
// =================================
//set neighbor kv pair nodes
template<typename key, typename elem>
void kvp_node<key, elem>::set_next(kvp_node<key, elem> *kvp) {
next = kvp;
}
template<typename key, typename elem>
void kvp_node<key, elem>::set_prev(kvp_node<key, elem> *kvp) {
prev = kvp;
}
template<typename key, typename elem>
void kvp_node<key, elem>::link_nodes(kvp_node<key, elem> *A, kvp_node<key, elem> *B) {
A->set_next(B);
B->set_prev(A);
}
// ==================================
//comparison operators
template<typename key, typename elem>
bool kvp_node<key, elem>::operator<(kvp_node<key, elem> &kvp)const{
return (k_val < kvp.key_()) ? (true) : (false);
}
template<typename key, typename elem>
bool kvp_node<key, elem>::operator>(kvp_node<key, elem> &kvp)const{
return (k_val > kvp.key_()) ? (true) : (false);
}
template<typename key, typename elem>
bool kvp_node<key, elem>::operator<=(kvp_node<key, elem> &kvp)const{
return (k_val <= kvp.key_()) ? (true) : (false);
}
template<typename key, typename elem>
bool kvp_node<key, elem>::operator>=(kvp_node<key, elem> &kvp)const{
return (k_val >= kvp.key_()) ? (true) : (false);
}
template<typename key, typename elem>
bool kvp_node<key, elem>::operator==(kvp_node<key, elem> &kvp)const{
return (k_val == kvp.key_()) ? (true) : (false);
}
// ==================================
//stream operators
template<typename key, typename elem>
std::ostream &operator<<(std::ostream &os, kvp_node<key, elem>const& kvp) {
os << kvp.key_() << ", " << kvp.elm_();
return os;
}
template<typename key,typename elem>
std::ostream &operator<<(std::ostream &os, kvp_node<key, elem>const* kvp) {
os << kvp->elm_();
return os;
}
int main( int argc, char* argv[] )
{
kvp_node<int,double> foo01( 1, 2 );
std::cout << foo01 << std::endl;
return 0;
}
答案 1 :(得分:1)
朋友模板通常难以正确实施。通常,最好的方法是将它们内联声明。这样,您就可以访问私人成员:
template<typename key, typename elem>
class kvp_node {
...
friend std::ostream& operator<<(std::ostream &os, kvp_node<key, elem> &kvp) {
os << kvp.e_val;
return os;
}
friend std::ostream& operator<<(std::ostream &os, kvp_node<key, elem> *kvp) {
os << kvp->e_val;
return os;
}
...
}
但是除了那些操作符之外我永远不会声明std::ofstream
的操作符,因为std::ofstream
是std::ostream
,所以第二个定义是无用的
我不会operator <<
把指针看作是一个引用。 cout
已经知道如何显示指向any的指针,并且它不显示指向的值。在API中显示指向的值会使将来的用户感到困惑。