void f(int);
void f(bool);
void f(void*);
f(0); // f(void*)가 아니라 f(int) 호출
f(NULL); // 컴파일되지 않을 수도 있지만, 보통은 f(int)를 호출함
// f(void*)를 호출하는 경우는 없음
f(nullptr); // f(void*)가 호출됨
// (1) auto 변수가 관여하는 상황
auto result = findRecord(/*인수들*/);
// 이렇게 사용하면 findRecord 반환 형식을 모르거나 파악하기 어려운 경우
// 반환값이 포인터 형식인지 정수 형식인지 명확하지 않음
if (result == 0)
{
// ...
}
// 이렇게 사용하면 중의성이 없음
if (result == nullptr)
{
// ...
}
// (2) 템플릿이 관여하는 상황
#include <iostream>
#include <vector>
#include <memory>
#include <mutex>
using namespace std;
class Widget {};
int f1(std::shared_ptr<Widget> spw);
double f2(std::unique_ptr<Widget> upw);
bool f3(Widget* pw);
std::mutex f1m, f2m, f3m;
template<typename FuncType, typename MuxType, typename PtrType>
auto lockAndCall(FuncType func, MuxType& mutex, PtrType ptr) -> decltype(func(ptr))
{
using MuxGuard = std::lock_guard<MuxType>;
MuxGuard g(mutex);
return func(ptr);
}
int main()
{
auto result1 = lockAndCall(f1, f1m, 0); // (1) 오류
auto result2 = lockAndCall(f2, f2m, NULL); // (2) 오류
auto result3 = lockAndCall(f3, f3m, nullptr); // (3) OK
}
(1), (2) 호출의 문제
lockAndCall
함수에 0
이나 NULL
을 넘겨주면 컴파일러는 형식을 파악하기 위해 템플릿 형식 연역을 적용함
두 타입 모두 정수 형식으로 연역되기 때문에 ptr로 넘겨주면 형식 오류가 발생함
(3)의 nullptr
은 std::nullptr_t
로 연역되므로 Widget*
로 암묵적 변환이 일어나 문제가 발생하지 않음
함수 오버로딩을 지칭하는 다른 용어라고 함
함수 오버로딩은 동일한 함수 이름을 가진 여러 함수를 정의하고 매개변수의 타입 또는 개수에 따라 적절한 함수를 호출하도록 하는 기능임
코드 상에서는 동일한 함수 이름처럼 보이지만, 컴파일러는 함수의 시그니처(함수 이름, 매개변수 타입, 반환 타입)를 기준으로 각 함수에 고유한 내부 이름을 부여함 -> 네임 맹글링