공부/그 외

C2678 : 이항 '~': 왼쪽 피연산자로 '~' 형식을 사용하는 연산자가 없거나 허용되는 변환이 없습니다.

sudo 2021. 9. 2. 01:02

~는 내가 쓰던 코드에서 선언한 타입이었다. ~에는 쓴 코드에서 사용한 연산자와 타입이 올 것이다.

 

에러에 관한 이야기를 하기 전에 짚고 넘어 가야 할 중요한 사실이 있는데 C++에서 const를 요구하는 인자에 non-const를 넘기는 것은 괜찮지만 non-const를 요구하는 곳에 const를 쓰면 에러가 생긴다(https://erlerobotics.gitbooks.io/erle-robotics-cpp-gitbook/content/advanced_topics_i/const_and_non-const.html)

 

예를 들어서 우리가 흔히 쓰는 복사 생성자는 인자로 const reference 타입을 받지만 인자로 넘겨줄 객체를 const로 선언하지 않아도 에러가 생기지 않는다. 예를 들어서

class A
{
public:
	A()
	{
	}

	A(int _Num)	:
		Num(_Num)
	{
	}

	A(const A& a)
	{
		std::cout << "Copy Constructor" << std::endl;
		Num = a.Num;
	}

	~A()
	{

	}

public:
	int Num;

	void func()
	{
		std::cout << "func" << std::endl;
	}
};

int main() 
{
	A a(3);
	A aa = a;
}

여기서는 복사 생성자 인자로 객체 a를 넘겨줬는데 a는 const로 선언된 객체가 아님에도 에러가 생기지 않는다(물론 a객체를 const로 선언해도 가능하다) 하지만 문제는 non-const를 요구하는 func() 함수를 const 객체가 호출하면 문제가 된다. 예를 들어서 

class A
{
public:
	A()
	{}

	A(int _Num)	:
		Num(_Num)
	{}

	A(const A& a)
	{
		std::cout << "Copy Constructor" << std::endl;
		Num = a.Num;
	}

	~A()
	{}

public:
	int Num;

	void func()
	{
		std::cout << "func" << std::endl;
	}
};

int main() 
{
	const A a(3);
	a.func();
}

이렇게 사용하면 에러가 생긴다.

 

이러한 사실을 염두에 두면 제목에 나온 에러를 처리할 수 있는데 내가 저런 에러를 마주하게 된 상황은 아래와 같다.

#pragma once

template <typename T>
class CSharedPtr
{
public:
	CSharedPtr()	:
		m_Ptr(nullptr)
	{
	}

	CSharedPtr(T* Ptr)
	{
		m_Ptr = Ptr;

		if (m_Ptr)
			m_Ptr->AddRef();
	}

	CSharedPtr(const CSharedPtr<T>& Ptr)
	{
		m_Ptr = Ptr.m_Ptr;

		if (m_Ptr)
			m_Ptr->AddRef();
	}

	~CSharedPtr()
	{
		if (m_Ptr)
			m_Ptr->Release();
	}

private:
	T* m_Ptr;

public:
	void operator = (T* Ptr)
	{
		if (m_Ptr)
			m_Ptr->Release();

		m_Ptr = Ptr;

		// 새로 지정된 레퍼런스 객체가 있을 경우 카운트를 1 증가시켜준다.
		if (m_Ptr)
			m_Ptr->AddRef();
	}

	void operator = (const CSharedPtr<T>& Ptr)
	{
		if (m_Ptr)
			m_Ptr->Release();

		m_Ptr = Ptr.m_Ptr;

		if (m_Ptr)
			m_Ptr->AddRef();
	}

	bool operator == (T* Ptr)	const
	{
		return m_Ptr == Ptr;
	}

	bool operator == (const CSharedPtr<T>& Ptr)	const
	{
		return m_Ptr == Ptr.m_Ptr;
	}

	bool operator != (T* Ptr)	const
	{
		return m_Ptr != Ptr;
	}

	bool operator != (const CSharedPtr<T>& Ptr)	const
	{
		return m_Ptr != Ptr.m_Ptr;
	}

	operator T* ()	
	{
		return m_Ptr;
	}

	T* operator -> () 
	{
		return m_Ptr;
	}
};
class CGameObject	:
	public CRef
{

public:
	CGameObject();
	CGameObject(const CGameObject& obj);
	virtual ~CGameObject();

protected:
	std::list<CSharedPtr<CCollider>> m_ColliderList;
    .
    .
    .// 여러가지 다른 멤버 함수/변수들
};
CGameObject::CGameObject(const CGameObject& obj)
{
	*this = obj;

	if (obj.m_Animation)
		m_Animation = obj.m_Animation->Clone();

	m_Animation->m_Owner = this;

	m_ColliderList.clear();

	auto	iter = obj.m_ColliderList.begin();
	auto	iterEnd = obj.m_ColliderList.end();

	for (; iter != iterEnd; ++iter)
	{
		m_ColliderList.push_back((*iter)->Clone());
	}
}

 

CGameObject의 복사 생성자의 obj인자는 const 객체이다. 따라서 obj의 멤버 변수인 m_ColliderList와 m_ColliderList안에 들어있는 CSharedPtr<CCollider>들도 const인 셈이다. 그런데 이 for문 내에서 CSharedPtr의 화살표 연산자(->)는 const를 요구하지 않는 멤버 함수이다. 이 멤버 함수를 const CSharedPtr<CCollider>로 호출하면 에러가 생길 수 밖에 없다.

 

따라서 에러를 해결하려면 아래와 같이 CSharedPtr의 화살표 연산자(->)끝에 const를 붙여주면 된다.

T* operator -> () const
{
	return m_Ptr;
}