most vexing parse
C++ Most Vexing Parse
간단히 설명하면, 문법의 모호함으로 인해 겪을 수 있는 문제로,
개발자는 인스턴스 생성을 의도하지만 컴파일러는 그것을 함수 선언으로 처리하는 문제이다.
class A {
public:
void doSomething() {}
};
int main() {
A a();
a.doSomething();
return 0;
}
main
함수의 첫 줄은 A
의 인스턴스를 선언하는 것으로 보이지만 실제로는
A 객체를 반환하는 함수를 선언한 것이다.
그러므로 gcc 로 컴파일 해 보면 다음과 같은 에러를 보게 된다.
t.cpp: In function 'int main()':
t.cpp:8:7: error: request for member 'doSomething' in 'a', which is of non-class type 'A()'
a.doSomething();
^~~~~~~~~~~
Clang++ 은 똑똑해서 정확한 에러 메세지를 보여준다.
t.cpp:7:8: warning: empty parentheses interpreted as a function declaration
[-Wvexing-parse]
A a();
^~
t.cpp:7:8: note: remove parentheses to declare a variable
A a();
^~
t.cpp:8:5: error: base of member reference is a function; perhaps you meant to call it
with no arguments?
a.doSomething();
^
()
1 warning and 1 error generated.
여기서 포인트는 문제를 해결하는 방법이 아니라, 이 컴파일 에러가 vexing parse 문제라는 점을 알아차리는 것이다.
위 예제와 같이 간단한 기본 생성자 선언에서는 간단히 괄호를 없애기만 해도 문제가 없다.
A a;
하지만, 다음과 같은 조금 더 복잡한 경우는 훨씬 더 문제를 바로 알아보기 힘들다.
class Timer {
public:
Timer();
};
class TimeKeeper {
public:
TimeKeeper(const Timer& t);
int get_time();
};
int main() {
TimeKeeper time_keeper(Timer());
return time_keeper.get_time();
}
wiki 에서 발췌
해결책은 대략 다음과 같이 요상한 모양으로 코딩하는 것이다.
// To add an extra pair of parentheses:
TimeKeeper time_keeper((Timer()));
// To use copy initialization:
TimeKeeper time_keeper = TimeKeeper(Timer());
// (In C++11 and later.) To use uniform initialization with braces:
TimeKeeper time_keeper{Timer()};
TimeKeeper time_keeper(Timer{});
TimeKeeper time_keeper{Timer{}};
위키를 참조
Written on September 28, 2019