문제

스트림을 반환하는 이진 트리에 대한 메소드를 구현하려고합니다. 메소드에서 반환 된 스트림을 사용하여 화면의 트리를 표시하거나 파일에 트리를 저장하고 싶습니다.

이 두 가지 방법은 이진 트리의 클래스에 있습니다.

선언 :

void streamIND(ostream&,const BinaryTree<T>*);
friend ostream& operator<<(ostream&,const BinaryTree<T>&);

template <class T>
ostream& operator<<(ostream& os,const BinaryTree<T>& tree) {
    streamIND(os,tree.root);
    return os;
}

template <class T>
void streamIND(ostream& os,Node<T> *nb) {
    if (!nb) return;
    if (nb->getLeft()) streamIND(nb->getLeft());
    os << nb->getValue() << " ";
    if (nb->getRight()) streamIND(nb->getRight());
}

이 방법은 트리 클래스를 사용하는 데 있습니다.

void UsingTree::saveToFile(char* file = "table") {
    ofstream f;
    f.open(file,ios::out);
    f << tree;
    f.close();
}

그래서 나는 binarytree 클래스의 연산자 "<<"에 사용하기 위해 : cout << tree and ofstream f << 트리를 과부하했지만 다음 오류 메시지를받습니다. Binarytree &) '

추신 트리는 단어 객체 (int가있는 문자열)를 저장합니다.

내 가난한 영어를 이해하기를 바랍니다. 고맙습니다! 그리고 나는 이와 같은 오류로 모든 시간을 낭비하기 때문에 필요한 모든 것을 설명하는 STL에 대한 초보자에게 좋은 텍스트를 알고 싶습니다.

편집 : savetofile ()의 트리가 선언됩니다 : binarytree <lord> tree.

도움이 되었습니까?

해결책

문제는 컴파일러가 템플릿을 사용하려고하지 않는다는 것입니다. operator<< 당신은 비 모전 버전을 제공했지만.

수업 내에서 친구를 선언하면 해당 기능의 선언을 둘러싸는 범위에서 주입합니다. 다음 코드는 non_template_test 지속적인 참조로 인수 :

class non_template_test
{
   friend void f( non_template_test const & );
};
// declares here:
// void f( non_template_test const & ); 

이 경우 템플릿 클래스에서도 마찬가지입니다.이 경우 직관적이지 않은 경우에도 동일합니다. 템플릿 클래스 본문 내에서 친구 함수를 선언하고 정의하지 않으면 정확한 인수로 자유 함수를 선언합니다. 템플릿 함수가 아닌 함수를 선언하고 있습니다.

template<typename T>
class template_test
{
    friend void f( template_test<T> const & t );
};
// for each instantiating type T (int, double...) declares:
// void f( template_test<int> const & );
// void f( template_test<double> const & );

int main() {
    template_test<int> t1;
    template_test<double> t2;
}

이러한 자유 함수는 선언되지만 정의되지 않았습니다. 여기서 까다로운 부분은 이러한 자유 함수가 템플릿이 아니라 정기적 인 자유 기능이 선언된다는 것입니다. 템플릿 함수를 믹스에 추가하면 다음과 같습니다.

template<typename T> class template_test {
   friend void f( template_test<T> const & );
};
// when instantiated with int, implicitly declares:
// void f( template_test<int> const & );

template <typename T>
void f( template_test<T> const & x ) {} // 1

int main() {
   template_test<int> t1;
   f( t1 );
}

컴파일러가 기본 함수에 도달하면 템플릿을 인스턴스화합니다. template_test 유형으로 int 그리고 그것은 자유 기능을 선언합니다 void f( template_test<int> const & ) 그것은 템플릿이 아닙니다. 전화를 찾을 때 f( t1 ) 두 가지가있다 f 일치하는 기호 : 비 템플릿 f( template_test<int> const & ) 언제 선언 (그리고 정의되지 않음) template_test 인스턴스화되었고 선언되고 정의 된 템플릿 버전 1. 비 모전 버전은 우선 순위를 차지하고 컴파일러가 일치합니다.

링커가 비 모전 버전을 해결하려고 할 때 f 상징을 찾을 수 없으므로 실패합니다.

우리는 무엇을 할 수 있습니까? 두 가지 해결책이 있습니다. 첫 번째 경우 우리는 컴파일러가 각 인스턴스화 유형에 대해 비 모전 함수를 제공합니다. 두 번째 경우에 우리는 템플릿 버전을 친구로 선언합니다. 그것들은 미묘하게 다르지만 대부분의 경우 동일합니다.

컴파일러가 우리를 위해 비 모전 함수를 생성하도록합니다.

template <typename T>
class test 
{
   friend void f( test<T> const & ) {}
};
// implicitly

이는 필요에 따라 많은 비 테일 플랜 프리 기능을 만드는 효과가 있습니다. 컴파일러가 템플릿 내에서 친구 선언을 찾을 때 test 그것은 선언을 찾을뿐만 아니라 구현도 찾아서 둘 다 둘 다 닫는 범위에 추가됩니다.

템플릿 버전을 친구로 만듭니다

템플릿을 친구로 만들려면 우리는 이미 그것을 선언하고 컴파일러에게 우리가 원하는 친구가 실제로 템플릿이 아니라고 말해야한다고 말해야합니다.

template <typename T> class test; // forward declare the template class
template <typename T> void f( test<T> const& ); // forward declare the template
template <typename T>
class test {
   friend void f<>( test<T> const& ); // declare f<T>( test<T> const &) a friend
};
template <typename T> 
void f( test<T> const & ) {}

이 경우 선언하기 전에 f 템플릿으로 템플릿을 선언해야합니다. 선언합니다 f 템플릿 먼저 선언해야합니다 test 주형. 친구 선언은 우리가 친구를 만드는 요소가 실제로 자유 함수가 아니라 템플릿임을 식별하는 각도 브래킷을 포함하도록 수정되었습니다.

문제로 돌아갑니다

특정 예로 돌아가서 가장 간단한 솔루션은 컴파일러가 친구 기능의 선언을 인화하여 귀하의 기능을 생성하도록하는 것입니다.

template <typename T>
class BinaryTree {
   friend std::ostream& operator<<( std::ostream& o, BinaryTree const & t ) {
      t.dump(o);
      return o;
   }
   void dump( std::ostream& o ) const;
};

해당 코드를 사용하면 컴파일러가 비 테일 플랜트를 생성하도록 강요하고 있습니다. operator<< 각각의 인스턴스화 유형에 대해 dump 템플릿의 방법.

다른 팁

템플릿 연산자 선언이 필요하지 않으며 다른 클래스에 대한 액세스 권한을 부여하기 위해 수업을 위해 운영자 "친구"를 선언해야합니다.이 경우 std :: cout

friend std::ostream& operator << ( std::ostream& os, BinaryTree & tree )
{
    doStuff( os, tree );
    return os;
}

권장 독서 : http://www.parashift.com/c++-faq-lite/friends.html

과부하 할 때 << 연산자 Const 참조를 사용하려는 경우 :

template <class T>
std::ostream& operator << (std::ostream& os, const BinaryTree<T>& tree) 
{
    // output member variables here... (you may need to make
    // this a friend function if you want to access private
    // member variables...

    return os;
}

전체 템플릿 정의 (프로토 타입뿐만 아니라)가 포함 된 (예 : .h, .hpp) 파일에 템플릿으로 구성되어 있고 별도의 컴파일이 함께 작동하지 않도록하십시오.

링커 @dribeas가 무엇을 사용하고 있는지 모르겠지만, 이로 인해 GNU 링커가 정의되지 않은 참조 오류를 유발할 수 있습니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top