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