[C++] 헤더 파일에 있는 struct를 리턴할 경우 궁금한 사항이 있습니다.

bellfive2000의 이미지

아래와 같은 경우

//<header>
struct PageCache {
    PageCache();
    ~PageCache();
    struct Page {
        void *mData;
        int mSize;
        int mOffset;
        ~Page();
    };
    int made;
    Page* acquirePage();
};
 
//<c++>
#include "PageCache.h"
PageCache::PageCache() {
    made = 0;
}
PageCache::~PageCache() {
}
PageCache::Page* PageCache::acquirePage() { //<== 해당 부분을 Page*로 리턴하게 하면 에러 발생
    Page* page;
    return page;
}

acquirePage란 함수에서 리턴값을 풀(PageCache::Page)로 써줘야만 compile 에러가 발생하지 않는 이유가 궁금합니다.
함수 내부에 있는 Page* page의 경우는 생략해서 쓸수 있는것에 비교했을 때 이상합니다.

물론 헤더 파일도 생략이 가능하네요.
얼핏 생각했을 땐 header의 경우는 Page struct 를 직접적으로 알 수 있기 때문에 생략 가능하다고 보여지는데
cpp는 여러 header들이 참조할 수 있기 때문에 풀로 써줘야 하나? 싶다가도 앞서 언급드린 함수 내부에서는 또 생략이 가능하기 때문에 헷갈리네요.

구글링해도 못 찾아 궁금한 점 올립니다.

익명 사용자의 이미지

방금 전에 "포인터에 const를 어떻게 붙였을 때 어떤 의미인가" 라는 비교적 간단한 문제에 답글 쓴답시고 C언어 선언 문법을 독해하며 시간을 들이붓고 왔는데 이번엔 이런 문제가... -_-;;

말씀하신 것과 같은 문제, 즉 그러니까,
네임스페이스 안의 네임스페이스 안의 클래스 안의 클래스 따위의 계층적인 구조를 만들 수 있는 C++에서 어떤 이름을 썼을 때 그 이름에 대응하는 선언을 어디서 찾냐,
하는 문제를, C++ 표준에서는 "Name lookup"이라고 합니다.

그 중에서 Scope resolution operator ::를 끼고 있는 이름을 찾는 걸 Qualified name lookup, 안 끼고 있는 이름을 찾는 건 Unqualified name lookup이라고 하고요,
지금 질문 내용은 Unqualified name인 "Page"를 써도 문제 없는 상황을 추려내 달라고 하시는 건데, 표준에서 이걸 설명하는 내용이 말 그대로 case-by-case로 전부 나열하는 거에요. 6페이지에 달합니다. (저는 지금 C++11 표준을 보고 있습니다.)

이걸 다 번역해드리기도 어렵고, 필요한 부분만 발췌해서 번역해드리기도 어렵고, 거 참 힘드네요. -_-;;; 정말로 딱 필요한 부분만 뽑겠습니다.

1. 헤더 파일의 Page* acquirePage();는 사용자 정의 클래스 PageCache의 정의 안에 있으면서 멤버 함수 몸체나 중첩 클래스 정의 밖에 있는데요.
이 경우 Unqualified name인 Page는 클래스 PageCache에서 "사용되기 전에 선언"되어 있으면 그것을 우선적으로 선택합니다. 즉 원하시는 PageCache::Page를 정확히 고르게 됩니다.

2. 소스 파일에서는 전역 범위에서 PageCache::acquirePage() 멤버 함수를 정의하고 있는데요. 여기서 한 가지 기준이 있습니다.
 (1) 멤버 함수의 declarator-id, 그러니까 이 경우엔 쉽게 말해서 PageCache::acquirePage 부분 뒤에서 사용되는 Unqualified name은,
  (i)일단 그 멤버함수 정의에서 해당 사용 전에 선언이 있다면 그걸 먼저 고릅니다.
  (ii)그런 선언이 없죠. 그러면 멤버 함수가 속한 클래스(이 경우엔 PageCache) 안에 해당하는 이름이 선언되어 있는지 봅니다. 여기서 탐색이 성공하고, PageCache::Page를 찾게 됩니다.

 (2) declarator-id 뒤에 있지 않은 이름은, 이 경우엔 그냥 전역 범위에 있는 것으로 보고, 전역 범위에 선언되었는지 봅니다. 없으면 바로 실패합니다.

이제 아시겠나요? PageCache::acquirePage() 멤버 함수 정의에서 반환값 타입 이름으로 쓰인 Page는 전역 범위에서 사용되었다고 보고 (2)를 적용하여 탐색이 실패하는 겁니다.
반면 멤버 함수 본체에 있는 Page* page;는 (1)이 적용되어 무사히 탐색이 끝나고 PageCache::Page에 대응됩니다.

이게 제가 할 수 있는 최선입니다.
설명이 모자란 거 저도 알아요. 근데 더 쉽고 유익하게 설명해주실 수 있는 분이 계시면 저도 그 분 답글 읽고 싶네요.
표준을 직접 읽고 해설해드리는 거 너무 어렵습니다.

익명 사용자의 이미지

덧.

C++의 Name lookup 규칙은 뭐 나름대로 합리적이긴 합니다만 모든 해괴한 케이스들에 대해서 올바르게 해석하려면 결국 휴먼 컴파일러가 될 수밖에 없습니다. 문법을 죄다 암기하고 적용하는 수밖에...
그리고 이걸 죄다 외우는 건 C언어의 declarator 문법을 다 외우는 것에 버금갈 정도로 힘들 것 같아요. 과연 오래 하다보면 체득이 될지 안될지는 솔직히 잘 모르겠네요.

또 덧붙이자면, C++03 declarator 문법은 C언어의 그것보다 훨씬 어렵습니다. C++11 declarator 문법은 C++03의 그것보다 훨씬 어렵고요.

bellfive2000의 이미지

굉장히 자세한 설명..^^

그리고 실제 저도 이런 문제에 정리할 기회가 있었는데 실제 이렇게 쓰기 귀찮기도 하고 어렵기도 한데 잘 설명해주셔서 감사합니다.

말씀하신대로 어려운 문제라서 지금 댓글을 읽어도 아주 클리어하게 이해가 된다고 보기 어렵긴하네요 ^________^

C++ 스펙 문서에서 못 찾고 있었는데 이젠 키워드로 찾아서 볼 수 있겠네요 그것도 정말 감사드립니다~~

댓글 달기

Filtered HTML

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

BBCode

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param>
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

Textile

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • You can use Textile markup to format text.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Markdown

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • Quick Tips:
    • Two or more spaces at a line's end = Line break
    • Double returns = Paragraph
    • *Single asterisks* or _single underscores_ = Emphasis
    • **Double** or __double__ = Strong
    • This is [a link](http://the.link.example.com "The optional title text")
    For complete details on the Markdown syntax, see the Markdown documentation and Markdown Extra documentation for tables, footnotes, and more.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Plain text

  • HTML 태그를 사용할 수 없습니다.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 줄과 단락은 자동으로 분리됩니다.
댓글 첨부 파일
이 댓글에 이미지나 파일을 업로드 합니다.
파일 크기는 8 MB보다 작아야 합니다.
허용할 파일 형식: txt pdf doc xls gif jpg jpeg mp3 png rar zip.
CAPTCHA
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.