[C++] 함수의 매개변수 타입을 명시적으로 강제하려면?

WestCoast·2022년 4월 7일
0

C, C++

목록 보기
9/12

궁금증


혹시 사용자로 하여금 함수의 매개변수 타입을 명시적으로 선언하도록 할 수 없을까?

그러니까 아래같은 경우를 원천봉쇄할 수는 없을까?

#include <iostream>
using namespace std;

void Test(int num)
{
	cout << "Test(int) : "<< num << endl;
}

int main()
{
	int iNum = 1;
	Test(iNum);

	double dNum = 1.5;
	Test(dNum);	// 적어도 대부분은 원하지 않을 동작...

	return 0;
}

출력값

Test(int) : 1
Test(int) : 1

그렇다면?


explicit 키워드를 사용하면 생성자 혹은 operator 등에서 타입을 명시적으로 나타내야만 컴파일러가 통과시켜주도록 강제할 수 있다.

#include <iostream>
using namespace std;

class Knight
{
public:
	// 생성자
	explicit Knight(int num)
	{
		cout << "explicit Knight(int num)" << num << endl;
	}
};

int main()
{
	int iNum = 2;

	//Knight knight1 = iNum;
	// Error! 암시적 변환은 컴파일러가 차단!

	Knight knight2 = static_cast<Knight>(iNum);
	// OK! 명시적으로 Knight 타입으로 변환하였음.

	return 0;
}

그렇다면 함수에 explicit 키워드를 사용하면 비슷한 결과를 얻을 수 있지 않을까?


안돼. 안봐줘. 돌아가.


// explicit 지정자로 선언할 수 없다며 컴파일 해주지 않는다.
explicit void Test(int)		
{
	cout << "Test(int)" << endl;
}

위처럼 쓸 수 있으면 좋겠지만... 컴파일러는 이런 문법을 용서치 않는다.(visual studio 기준)

혹시 함수도 이런 명시적으로 선언하도록 강요할 수 있는 키워드나 방법이 정말 없을까?


그 방법. 여기 있습니다!


#include <iostream>
using namespace std;

// 이 부분 주목!
// void Test(double) 시그니쳐는 delete 해버립니다.
void Test(double) = delete;	

void Test(int)
{
	cout << "Test(int)" << endl;
}

int main()
{
	int iNum = 1;
	Test(iNum);	// OK!

	double dNum = 1.5;
	//Test(dNum);	// Error! dNum이 int 타입이 아닙니다.
	

	Test(static_cast<int>(dNum));
	// OK! int 타입으로 명시적 형변환 해주었습니다.

	return 0;
}

void Test(double) = delete; 이 부분이 알파이자 오메가이며 말하고자 하는 것의 전부다.
특정 매개변수 타입의 함수 시그니쳐를 삭제(delete) 해버리자는 것.
이렇게 하면 double 타입의 매개변수를 갖는 Test 함수는 존재하지도 않으므로 사용자의 실수가 원천봉쇄 된다!

하지만 뭔가 부족하다. 뭔가... 그럼 사용자가 float 타입을 넣어주면 어떡해? 비슷한 일이 있을 때마다 저걸 매번 한 줄씩 추가해줘야 되는 건가?


template으로 일반화!


#include <iostream>
using namespace std;

// void Test(T) 시그니쳐는 delete 해버립니다.
template<typename T> void Test(T) = delete;

void Test(int)
{
	cout << "Test(int)" << endl;
}

int main()
{
	int iNum = 1;
	Test(iNum);	// OK!

	double dNum = 1.5;
	//Test(dNum);	// Error! dNum이 int 타입이 아닙니다.
	
	Test(static_cast<int>(dNum));
	// OK! int 타입으로 명시적 형변환해주었습니다.


	float fNum = 2.5f;
	// Test(fNum);	// Error! int 타입이 아닙니다.

	Test(static_cast<int>(fNum));
	// OK! int 타입으로 명시적 형변환해주었습니다.

	return 0;
}

이걸 void Test(double) = delete;
이렇게 template<typename T> void Test(T) = delete;
바꿔주면 Test(int) 시그니쳐를 가진 함수 외의 모든 매개변수 타입을 삭제해버릴 수 있다.
즉, 매개변수가 int 타입이 아니라면 사용 불가하게 막아준 것!

이로써 완벽하게 하고자 하는 바를 이루었다.
이 방법은 함수에 대해서만이 아니라, 생성자 등에도 사용이 가능하므로 필요하다면 활용해보도록 하자.

profile
게임... 만들지 않겠는가..

0개의 댓글