[ Effective C++ ] 항목 46 : 타입 변환이 바람직할 경우에는 비멤버 함수를 클래스 템플릿 안에 정의해 두자

Minsu._.Lighting·2023년 12월 14일
0

[ Effective C++ ] 정리 모음집
" C++ 프로그래머의 필독서, 스콧 마이어스의 Effective C++ 를 읽고 내용 요약 / 정리 "

[핵심]

" 클래스 안에 비멤버 함수를 선언하는 유일한 방법 '프렌드'! "

  • 모든 매개변수에 대해 암시적 타입 변환을 지원하는 템플릿과 관계가 있는 함수를 제공하는 클래스 템플릿을 만들려고 한다면, 이런 함수는 클래스 템플릿 안에 프렌드 함수로서 정의하자!

💡 템플릿 인자 추론 과정에서는 암시적 타입 변환이 고려되지 않는다

📌 포인터의 암시적 변환

template<typename T>
class Rational
{
public:
	Rational(const T& numerator = 0,
    		const T& denominator = 1);
            
	const T numerator() const;
    const T denominator() const;
    ...
};

template<typename T>
const Rational<T> operator* (const Rational<T>& lhs,
							const Rational<T>& rhs,
{ ... }

Rational<int> oneHalf(1, 2);

Rational<int> result = oneHalf * 2;	// 에러!
  • 컴파일러는 operator* 매개변수들의 T가 무엇인지 모른다
    - 첫번째 인자 oneHalfRational<int> 이기 때문에 T가 int 라는걸 알지만, 두번째 인자는 기본 int 형식이다. 암시적 변환이 고려되지 않기에 컴파일러는 알 수 없다.

📌 프렌드 선언을 이용해 컴파일 오류를 막아보자!

template<typename T>
class Rational
{
public:
	...
friend
	const Rational operator*(const Rational& lhs,
    						const Rational& rhs);
};

template<typename T>
const Rational<T> operator*(const Rational<T>& lhs,
							const Rational<T>& rhs)
{ ... }
  • 클래스 템플릿 안에 프렌드 함수를 넣어 함수 템플릿으로서의 성격을 주지 않고 특정한 함수 하나를 나타낼 수 있다

📢 컴파일은 되지만 링크가 되지 않는다!
- Rational 안에 선언만되고 정의는 되지 않았기에!

📌 링크 문제 해결 1 - 함수의 본문을 선언부와 붙이자!

template<typename T>
class Rational
{
public:
friend const Rational operator*(const Rational& lhs,
								const Rational& rhs)
{
	return Rational(lhs.numerator() * rhs.numerator(),
    				lhs.denominator() * rhs.denominator());
}
};
  • 가장 간단한 방법

  • 프렌드 함수를 선언 했지만 클래스의 public 영역이 아닌 부분에 접근하는 것과 프렌드 권한은 아무런 상관이 없다
    - 공교롭게도 클래스 안에 비멤버 함수를 선언하는 유일한 방법이 '프렌드' 였을 뿐

📌 링크 문제 해결 2 - 프렌드 함수는 도우미만 호출하게 만들기

template<typename T> class Rational;

template<typename T>
const Rational<T> doMultiply(const Rational<T>& lhs,
							const Rational<T>& rhs);

template<typename T>
class Rational
{
public:
	...
friend
	const Rational<T> operator*(const Rational<T>& lhs,
    							const Rational<T>& rhs)
	{ return doMultiply(lhs, rhs); }
	...
};

template<typename T>
const Rational<T> doMultiply(const Rational<T>& lhs,
							const Rational<T>& rhs)
{
	return Rational<T>(lhs.numerator() * rhs.numerator(),
    					lhs.denominator() * rhs.denominator());
}
  • 함수의 본문을 선언부와 붙일 때 본문이 복잡하다면 사용할만하다
    - 암시적 인라인화가 진행되기 때문
profile
오코완~😤😤

0개의 댓글

관련 채용 정보