연산자 <<는 정확히 하나의 인수를 가져야합니다.


94

#include "logic.h"
...

class A
{
friend ostream& operator<<(ostream&, A&);
...
};

logic.cpp

#include "a.h"
...
ostream& logic::operator<<(ostream& os, A& a)
{
...
}
...

컴파일하면 다음과 같이 표시됩니다.

std :: ostream & logic :: operator << (std :: ostream &, A &) '는 정확히 하나의 인수를 가져야합니다.

무엇이 문제입니까?

답변:


132

문제는 클래스 내부에서 정의한다는 것입니다.

a) 두 번째 인수가 암시 적 ( this)이고

b) 원하는 것을 수행하지 않습니다 std::ostream.

자유 함수로 정의해야합니다.

class A { /* ... */ };
std::ostream& operator<<(std::ostream&, const A& a);

9
또한 그는 그것을 친구 함수로 선언하고 멤버 함수로 정의합니다.
asaelr

en.cppreference.com/w/cpp/language/operators 에서 언급했듯이 "std :: istream & 또는 std :: ostream &을 왼쪽 인수로 사용하는 operator >> 및 operator <<의 오버로드는 삽입 및 추출 연산자. 사용자 정의 유형을 올바른 인수 (a @ b의 b)로 취하므로 비 구성원으로 구현해야합니다. "
Morteza

49

친구 함수는 멤버 함수가 아니기 때문에 문제는 다음 operator<<의 친구로 선언한다는 것 입니다 A.

 friend ostream& operator<<(ostream&, A&);

그런 다음 클래스의 멤버 함수로 정의하십시오. logic

 ostream& logic::operator<<(ostream& os, A& a)
          ^^^^^^^

logic클래스인지 네임 스페이스 인지 혼란 스럽 습니까?

오류는 operator<<두 개의 인수 를 사용하는 멤버를 정의하려고했기 때문에 암시 적 this매개 변수를 포함하여 세 개의 인수를 사용합니다 . 연산자는 두 개의 인수 만 사용할 수 있으므로 작성 a << b시 두 개의 인수는 ab입니다.

당신은 정의 할 ostream& operator<<(ostream&, const A&)A와 - 구성원 기능, 확실히의 구성원으로 logic는 그 클래스와는 아무 상관이 없기 때문에!

std::ostream& operator<<(std::ostream& os, const A& a)
{
  return os << a.number;
}

3

템플릿 클래스에서이 문제가 발생했습니다. 다음은 내가 사용해야하는보다 일반적인 솔루션입니다.

template class <T>
class myClass
{
    int myField;

    // Helper function accessing my fields
    void toString(std::ostream&) const;

    // Friend means operator<< can use private variables
    // It needs to be declared as a template, but T is taken
    template <class U>
    friend std::ostream& operator<<(std::ostream&, const myClass<U> &);
}

// Operator is a non-member and global, so it's not myClass<U>::operator<<()
// Because of how C++ implements templates the function must be
// fully declared in the header for the linker to resolve it :(
template <class U>
std::ostream& operator<<(std::ostream& os, const myClass<U> & obj)
{
  obj.toString(os);
  return os;
}

이제 : * 내 toString () 함수가 cpp에 들어가면 인라인 될 수 없습니다. * 헤더에 일부 코드가있어 제거 할 수 없습니다. * 연산자는 인라인되지 않은 toString () 메서드를 호출합니다.

operator <<의 본문은 friend 절 또는 클래스 외부에서 선언 할 수 있습니다. 두 옵션 모두 추악합니다. :(

오해하거나 뭔가 빠졌을 수도 있지만 연산자 템플릿을 앞으로 선언하면 gcc에서 링크되지 않습니다.

이것도 작동합니다.

template class <T>
class myClass
{
    int myField;

    // Helper function accessing my fields
    void toString(std::ostream&) const;

    // For some reason this requires using T, and not U as above
    friend std::ostream& operator<<(std::ostream&, const myClass<T> &)
    {
        obj.toString(os);
        return os;
    }
}

operator <<를 구현하기 위해 템플릿 화되지 않은 부모 클래스를 사용하고 가상 toString () 메서드를 사용하면 헤더에서 선언을 강제하는 템플릿 문제를 피할 수 있다고 생각합니다.


0

operator<<멤버 함수로 정의 하면 비 멤버를 사용한 경우와는 다른 분해 구문을 갖게됩니다 operator<<. 비 멤버 operator<<는 멤버 operator<<가 단항 연산자 인 이항 연산자입니다.

// Declarations
struct MyObj;
std::ostream& operator<<(std::ostream& os, const MyObj& myObj);

struct MyObj
{
    // This is a member unary-operator, hence one argument
    MyObj& operator<<(std::ostream& os) { os << *this; return *this; }

    int value = 8;
};

// This is a non-member binary-operator, 2 arguments
std::ostream& operator<<(std::ostream& os, const MyObj& myObj)
{
    return os << myObj.value;
}

그래서 .. 진짜 어떻게 부르나요? 연산자는 어떤면 operator<<(...)에서 이상합니다. 이해를 돕기 위해 머리 속에 구문 을 작성하도록 도전하겠습니다 .

MyObj mo;

// Calling the unary operator
mo << std::cout;

// which decomposes to...
mo.operator<<(std::cout);

또는 멤버가 아닌 이항 연산자를 호출 할 수 있습니다.

MyObj mo;

// Calling the binary operator
std::cout << mo;

// which decomposes to...
operator<<(std::cout, mo);

이러한 연산자를 멤버 함수로 만들 때 이러한 연산자가 직관적으로 작동하도록 할 의무가 없습니다. operator<<(int)원하는 경우 일부 멤버 변수를 왼쪽으로 이동하도록 정의 할 수 있습니다. 얼마나 많은 댓글이 있더라도 사람들이 경계를 늦출 수 있음을 이해하십시오. 쓰다.

거의 마지막으로, 교환 원 호출에 대한 두 분해가 모두 유효한 경우가있을 수 있으며 여기에서 문제가 발생할 수 있으며 대화를 연기 할 것입니다.

마지막으로, 이항 연산자처럼 보이는 단항 멤버 연산자를 작성하는 것이 얼마나 이상 할 수 있는지 주목하십시오 (멤버 연산자를 가상으로 만들 수 있습니다 ..... 또한이 경로를 계승하지 않고 실행하려고 시도합니다 .... )

struct MyObj
{
    // Note that we now return the ostream
    std::ostream& operator<<(std::ostream& os) { os << *this; return os; }

    int value = 8;
};

이 구문은 이제 많은 코더를 짜증나게 할 것입니다 ....

MyObj mo;

mo << std::cout << "Words words words";

// this decomposes to...
mo.operator<<(std::cout) << "Words words words";

// ... or even further ...
operator<<(mo.operator<<(std::cout), "Words words words");

cout여기 체인에서 두 번째 인수가 어떻게되는지 주목 하십시오 .... 이상하지 않습니까?

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.