模板化的流操作符,未解析的外部

时间:2015-10-18 17:24:17

标签: c++ templates

在之前的项目中,我遇到了类似的错误,因此我决定从新方法开始,并且仍然遇到同样的问题。我有一个键值对模板类,除流操作符外,一切正常。我有<<的模板接受kvp_node<key, elem> &kvpkvp_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

我如何使用所有其他类成员但流操作符不起作用?

2 个答案:

答案 0 :(得分:1)

我得到了它的工作。这是我的变化。 (我对提交内容进行了调整,所以在我修改格式时请原谅我。)

  • 删除了不同运营商的好友功能。既然你有吸气剂,那就足够了。
  • 让所有getters const。如果您尝试在STL容器中使用它,则会因丢弃限定符而出错。
  • 让所有流操作符获取类的const实例。

代码

  #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中显示指向的值会使将来的用户感到困惑。