문제

인라인 멤버가있는 클래스가 있지만 나중에 헤더에서 구현을 제거하기로 결정하여 기능의 멤버 본문을 CPP 파일로 옮겼습니다. 처음에 나는 방금 헤더 파일 (sloppy me)에 인라인 서명을 남겼고 프로그램이 올바르게 연결되지 않았다. 그런 다음 헤더를 수정했고 물론 모두 잘 작동합니다.

그러나 인라인은 완전히 선택적이지 않았습니까?

코드 :

첫 번째:

//Class.h
class MyClass
{
   void inline foo()
   {}
};

다음으로 변경되었습니다 (링크하지 않음) :

//Class.h
class MyClass
{
   void inline foo();
};

//Class.cpp
void MyClass::foo()
{}

그리고 나서 (잘 작동합니다) :

//Class.h
class MyClass
{
   void foo();
};

//Class.cpp
void MyClass::foo()
{}

나는 인라인이 선택 사항이라고 생각했고, 나는 경고에 대한 경고를받을 수 있다고 상상했지만 링크 오류는 기대하지 않았다. 이 경우 컴파일러가해야 할 정확한/표준 일은 무엇입니까? 표준에 따라 오류가 발생할 자격이 있습니까?

도움이 되었습니까?

해결책

실제로, 인라인 기능이 기능한다고 말하는이 정의 규칙이 있습니다. ~ 해야 하다 사용되는 모든 번역 장치에서 정의됩니다. gory 세부 사항은 다음과 같습니다. 첫 번째 3.2/3:

모든 프로그램에는 해당 프로그램에 사용되는 모든 비 인화 함수 또는 객체의 정의가 정확히 하나를 포함해야합니다. 진단이 필요하지 않습니다. 정의는 프로그램에 명시 적으로 나타나거나 표준 또는 사용자 정의 라이브러리에서 찾을 수 있거나 (적절한 경우) 암시 적으로 정의됩니다 (12.1, 12.4 및 12.8 참조). 인라인 함수는 사용되는 모든 번역 단위에서 정의되어야합니다.

그리고 물론 7.1.2/4:

인라인 함수는 사용되는 모든 번역 단위에서 정의되어야하며 모든 경우에 정확히 동일한 정의를 가져야합니다 (3.2). [참고 : 변환 단위에 정의가 나타나기 전에 인라인 함수에 대한 호출이 발생할 수 있습니다. ] 외부 연결이있는 함수가 하나의 번역 유닛에서 인라인으로 선언되면, 모든 번역 장치에서 인라인으로 선언된다. 진단이 필요하지 않습니다. 외부 연계가있는 인라인 함수는 모든 번역 단위에 동일한 주소를 가져야합니다. 외부 인라인 함수의 정적 로컬 변수는 항상 동일한 객체를 나타냅니다. 외부 인라인 함수의 문자열 문자는 다른 번역 단위의 동일한 객체입니다.

그러나 클래스 정의 내에서 기능을 정의하면 암시 적으로 다음과 같이 선언됩니다. inline 기능. 이를 통해 프로그램에 인라인 함수 본문이 여러 번 포함 된 클래스 정의를 포함시킬 수 있습니다. 함수는 가지고 있기 때문에 external 연결, 그 정의는 같은 기능 (또는 더 많은 gory- 동일합니다 entity).

내 주장에 대한 Gory 세부 사항. 첫 번째 3.5/5:

또한, 클래스의 이름에 외부 연결이있는 경우 멤버 기능, 정적 데이터 구성원, 클래스 또는 클래스 범위의 열거에는 외부 연결이 있습니다.

그 다음에 3.5/4:

네임 스페이스 스코프를 갖는 이름은 [...] 이름이 지명 된 클래스 (9 항) 또는 클래스가 연결 목적으로 typedef 이름을 갖는 TypEdef 선언에 정의 된 이름이없는 클래스 인 경우 외부 연결이 있습니다.

이 "연결 목적의 이름"이 재미있는 것입니다.

typedef struct { [...] } the_name;

지금부터 여러 정의가 있습니다 같은 엔티티 귀하의 프로그램에서 ODR의 또 다른 일이 귀하를 제한합니다. 3.2/5 지루한 물건을 따릅니다.

클래스 유형 (9 항), 열거 유형 (7.2), 외부 연결 (7.1.2) [...]가있는 인라인 함수의 정의가 하나 이상있을 수 있습니다. 그리고 정의가 다음 요구 사항을 충족 시켰습니다. D라는 기업이 하나 이상의 번역 장치에 정의 된 기업을 감안할 때

  • d의 각 정의는 동일한 시퀀스의 토큰으로 구성되어야한다. 그리고
  • D의 각 정의에서, 3.4에 따라 찾은 해당 이름은 D의 정의 내에 정의 된 엔티티를 지칭하거나, 과부하 해상도 (13.3) 후 및 부분 템플릿 전문화 (14.8)와 일치 한 후 동일한 엔티티를 참조해야한다. .삼) [...

나는 지금 중요하지 않은 것들을 잘라냅니다. 위는 인라인 기능에 대해 기억해야 할 두 가지 중요한 것입니다. 외부 인라인 함수를 여러 번 정의하지만 다르게 정의하거나 다른 엔티티로 사용 된 이름을 정의하는 경우 정의되지 않은 동작을 수행합니다.

기능이 사용되는 모든 TU에서 기능을 정의해야한다는 규칙은 기억하기 쉽습니다. 그리고 그것은 동일하다는 것도 기억하기 쉽습니다. 그러나 그 이름 해상도는 어떻습니까? 여기에 몇 가지 예. 정적 기능을 고려하십시오 assert_it:

static void assert_it() { [...] }

이제 그 이후로 static 내부 연계를 제공하면 여러 번역 단위에 포함시킬 때 각 정의는 다른 엔티티. 이것은 당신이라는 것을 의미합니다 ~ 아니다 사용할 수 있습니다 assert_it 프로그램에서 여러 번 정의 될 외부 인라인 함수에서 다음과 같이 assert_it 하나의 TU에서, 그러나 다른 TU에서 같은 이름의 다른 엔티티에. 이 모든 것이 지루한 이론이며 컴파일러가 불평하지 않을 것이라는 것을 알 수 있지만, 특히이 예는 ODR과 엔티티의 관계를 보여줍니다.


다음은 특정 문제로 다시 돌아 오는 것입니다.

다음과 같은 것입니다.

struct A { void f() { } };
struct A { inline void f(); }; void A::f() { } // same TU!

그러나 함수는 비 인화이기 때문에 이것은 다릅니다. 당신은 하나 이상의 정의를 가지고 있기 때문에 당신은 ODR을 위반할 것입니다. f 헤더를 두 번 이상 포함하는 경우

struct A { void f(); }; void A::f() { } // evil!

지금 당신이 넣으면 inline 선언에 f 클래스 내부에서는 헤더에서 정의하면 생략 한 다음 위반합니다. 3.2/3 (그리고 7.1.2/4 해당 번역 장치에서 함수가 정의되지 않기 때문에 같은 것을 더 정교하게 말합니다.

C (C99)에서 인라인은 C ++와 다른 의미를 갖습니다. 외부 인라인 함수를 작성하는 경우 먼저 좋은 용지 (바람직하게는 표준)를 읽어야합니다 (바람직하게는 표준). C의 정적 인라인 함수는 처리하기 쉽습니다. 일반적인 "인라인 대체"힌트를 갖는 것 외에 다른 기능과 마찬가지로 행동합니다. inline C와 C ++ 모두에서 인라인 치환 힌트로만 제공됩니다. STATIC는 이미 사용될 때마다 다른 엔티티를 생성하기 때문에 (내부 연결로 인해) inline 인라인 치수 힌트를 추가 할 것입니다.

다른 팁

메소드가 실제로 상환되는지 여부는 컴파일러의 단독 재량입니다. 그러나 인라인 키워드의 존재는 또한 방법의 연결에 영향을 미칩니다.

C ++ Linkage는 내 전문 분야가 아니므로 더 나은 설명을 위해 링크를 연기하겠습니다.

또는 당신은 그냥 기다릴 수 있습니다 litb 한 시간 정도 안에 Gory 세부 사항을 제공하려면;)

참고 사항 : 메소드가 인라인으로 선언되면 정의는 선언과 함께해야합니다.

Harshath.jr의 답변과 관련하여 정의가 "인라인"키워드가 있고 해당 정의가 동일한 헤더에서 사용할 수있는 경우 방법을 인라인으로 선언 할 필요가 없습니다. :

class foo
{
  void bar();
};

inline void foo::bar()
{
  ...
}

이것은 빌드가 의지 여부에 따라 방법을 조건부로 인용하는 데 유용합니다. "디버그" 또는 "풀어 주다"그렇게 좋아 :

// Header - foo.h

class foo
{
  void bar();  // Conditionally inlined.
};

#ifndef FOO_DEBUG
# include "foo.inl"
#endif

"인라인"파일은 다음과 같습니다.

// Inline Functions/Methods - foo.inl
#ifndef FOO_DEBUG
# define FOO_INLINE inline
#else
# define FOO_INLINE
#endif

FOO_INLINE void foo::bar()
{
  ...
}

그리고 구현은 다음을 좋아할 수 있습니다.

// Implementation file - foo.cpp
#ifdef FOO_DEBUG
# include "foo.inl"
#endif

...

정확히 예쁘지는 않지만 공격적인 인라인이 디버깅 두통이 될 때 사용됩니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top