2017-01-17 8 views
0

인자를 취하지 않는 함수 선언의 매개 변수로 void을 사용할지 여부에 대한 모호성에 가장 많이 사용되는 구문 분석이 뿌리를 내리고 있습니까?인자를 취하지 않는 함수의 선언에 void를 사용하는 것을 지정하면 가장 잘하는 구문 분석이 수행됩니까?

예를 들어, 다음 코드는 g ++ (v7.2.1) 및 Xcode (Apple LLVM 버전 7.0.2 (clang-700.1.81)) 컴파일러 모두에서 오류없이 컴파일되고 정상적으로 실행됩니다.

이것은 빈 매개 변수 목록이 임의의 수의 인수를 나타내는 ANSI-C 표준 이전까지 거슬러 올라갑니다. 컴파일러에서 이전 버전과의 호환성을 통해 오늘날 우리를 괴롭 히고 있습니다. 문제에 대해 다소 혼란 스러울 것 같습니다. 적어도 오류를 발생시키지 않으면 위의 경고를 생성해야합니까?

저는 여기에 주현 (또는 아마 파이프 꿈!)이있었습니다. Most Vexing Parse가 빈 함수 선언 목록에서 void의 사용에 대한 모호성에 뿌리를두고있는 것일 수 있습니까?

또 다른 예를 들어, 다음과 같은 위키 백과의 예를 참조하기 :

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(); 
} 

이 해석 될 수 있기 때문에 라인

TimeKeeper time_keeper(Timer()); 

은, 겉으로는 모호 하나

  • 변수로 TimeKe 클래스의 time_keeper 변수에 대한 정의 Timer 클래스의 익명 인스턴스 또는
  • TimeKeeper 형식의 개체를 반환하고 이 형식 Timer를 반환하는 포인터 인 단일 (이름이없는) 매개 변수가있는 time_keeper 함수의 함수 선언에 초기화되었습니다. 입력). https://en.wikipedia.org/wiki/Most_vexing_parse

    이제, 우리는이 제거되지 않습니다, 아니 변수와 함수를 선언 할 때 void 사용되어야 함을 지정하면 (:

참조 (C와 C++에서 함수 오브젝트 # 참조) hackishly, 근본적으로 제거하지!) 모호성? 문제의 라인은 다음 함수 선언 의심의 여지를 남겨두고 다음 될 것입니다 :

int main() { 
    TimeKeeper time_keeper(Timer(void)); 
    return time_keeper.get_time(); 
} 

이이 문제가 논의 철도청, 다시 모든 길을 간다 :

때문에 getline 및 copy의 특수 버전에는 인수가 없기 때문에 로직은 파일 시작 부분에 프로토 타입이 getline()copy()이어야한다고 제안합니다. 그러나 이전 C 프로그램과의 호환성을 위해 표준에서는 빈 형식의 목록을 구식 선언으로 사용하고 모든 인수 목록 검사를 해제합니다. 명시 적으로 비어있는 목록에 단어 void을 사용해야합니다. [커니 핸 & 리치, C 프로그래밍 언어, 1988, PGS 32 ~ 33]

와 ..

빈 인수 목록의 특별한 의미에 오래된 C 프로그램을 허용하기위한 것입니다 새 컴파일러로 컴파일하십시오. 그러나 새 프로그램에서 사용하는 것은 좋지 않습니다. 함수가 인수를 취하는 경우 을 선언하십시오. 인수가 없으면 void [ibid, Pg. 73]

참조 : is f(void) deprecated in modern C and C++

+1

"경고를 생성하지 않으면 오류를 발생시키지 않을까요?" 아니, 왜 그렇게 생각하니? 이 코드는 두 개의 함수를 선언하고 그 중 하나에 대한 정의를 제공하고 그 함수를 호출합니다. –

+2

가장 짜증나는 구문 분석 방법은'foo bar();'라는 함수에서'foo'를'foo'라는 변수로''bar''라는 변수를''기본으로 생성 된 변수로 분리하는 것입니다. – NathanOliver

+0

@linuxeveloper 2, 함수 선언과 정의 사이의 인수 불일치 때문에; 특히, 선언은''void'' 인수를 지정하고, 정의는 정수 인수를 지정합니다. – kmiklas

답변

2

함수 정의도 선언된다. 당신은 당신이 asdf의 두 가지 버전, int 하나의 복용 아무것도 복용하지 하나를 선언 한

int asdf(void); 
int asdf(int a) { 
    return a; 
} 

이있을 때 그 의미한다. 그런 다음이 int 버전이 정의되어 있기 때문에 그 아무 문제가 없습니다

std::cout << asdf(6) << std::endl; //-> 6 

를 사용할 때 int 버전을 사용하기에 이동합니다.

당신이 그것을 선언하지만 정의했기 때문에 당신이 asdf을 '에

정의되지 않은 참조를 얻을해야 할 때

asdf(); 

를 사용하려고하면 문제가 될 것이 무엇

() '

정의가 없으므로 이것은 가장 지독한 구문 분석과는 아무런 관련이 없지만 함수 선언과 정의의 차이점입니다.

+0

아, 인수 목록이 다르기 때문에 함수 서명이 다르며 "asdf (6)"호출이 "int asdf (int a) {'', correct? – kmiklas

+1

@kmiklas 예. 함수에 오버로드가 발생했습니다. 'void' 오버로드에 대한 정의를 제공하지 않았습니다. – NathanOliver

+0

Thx. 나는 Vexing Parse에 대한 해결책을 뿌리 내리고 나무를 통해 숲을 놓친이 사업에 얽혀 있습니다. – kmiklas

2

귀하의 제안으로 모호성이 완전히 제거되지는 않습니다.

고려 : 그것은, 유형 Foo의 지역 변수 bar를 선언 생성자에 std::string를 통과 할 수 있었던 것처럼

#include <string> 

struct Foo { ... }; 

int main(int argc, char **argv) { 
    Foo bar(std::string(argv[1])); 
} 

이 보인다.

그러나 실제로 의미하는 것입니다 :

Foo bar(std::string *argv); 

즉, "std::string 포인터"유형의 인수를 취하여 Foo을 반환하는 함수로 bar을 선언하십시오.

이 예는 void을 추가하여 수정할 수 없습니다.