C ++에서 typedef의 전방 선언


235

컴파일러에서 typedef를 전달할 수없는 이유는 무엇입니까?

불가능하다고 가정하면 포함 트리를 작게 유지하는 가장 좋은 방법은 무엇입니까?

답변:


170

앞으로 typedef를 수행 할 수 있습니다. 그러나 할

typedef A B;

먼저 선언해야합니다 A:

class A;

typedef A B;

11
기술적으로 "forward-typedef"(예 : "typedef A;"를 쓸 수 없음)는 할 수 없지만, 위의 트릭을 사용하여 OP가 달성하고자하는 것을 거의 확실하게 달성 할 수 있기 때문에 결국 +1입니다.
j_random_hacker

9
그러나 typedef가 변경되면 모든 전방 선언도 변경할 수 있습니다. 이전 인터페이스와 새로운 typedef가 동일한 인터페이스를 가진 유형을 사용하는 경우 놓칠 수 있습니다.
math

50
일반적으로 이것은 유용한 솔루션이 아닙니다. 예를 들어 typedef, 순방향 선언을 사용하여 복잡한 다중 레벨 템플리트 유형 의 이름을 지정하는 경우 다소 복잡하고 어렵습니다. 말할 것도없이 기본 템플릿 인수에 숨겨진 구현 세부 정보를 살펴볼 필요가 있습니다. 그리고 최종 솔루션은 길고 읽을 수없는 코드입니다 (특히 유형이 다양한 네임 스페이스에서 온 경우)는 원래 유형으로 변경되기 쉽습니다.
Adam Badura

3
또한 이것은 "구현 세부 사항"(완전하지는 않지만 여전히 ...)을 보여 주지만 앞으로 선언의 아이디어는 숨기려고했습니다.
Adam Badura

3
@windfinder : 그렇습니다 : template <class T> class A; typedef A <B> B;
milianw

47

나와 같은 당신을 위해, 일부 C ++ 코드에서 typedef를 사용하여 정의 된 C 스타일 구조체를 선언하려고하는 사람들은 다음과 같은 해결책을 찾았습니다 ...

// a.h
 typedef struct _bah {
    int a;
    int b;
 } bah;

// b.h
 struct _bah;
 typedef _bah bah;

 class foo {
   foo(bah * b);
   foo(bah b);
   bah * mBah;
 };

// b.cpp
 #include "b.h"
 #include "a.h"

 foo::foo(bah * b) {
   mBah = b;
 }

 foo::foo(bah b) {
   mBah = &b;
 }

4
@LittleJohn이 솔루션의 문제점은 더미 이름 _bah가 공개 API의 일부로 간주되지 않는다는 것입니다. 앞으로 delcare FILE을 참조하십시오.
user877329

23

"fwd typedef 선언"을하려면 클래스 또는 구조체를 fwd 선언 한 다음 typedef 선언 된 유형을 사용할 수 있습니다. 컴파일러는 여러 개의 동일한 typedef를 사용할 수 있습니다.

긴 형식 :

class MyClass;
typedef MyClass myclass_t;

짧은 형식:

typedef class MyClass myclass_t;

이것은 가장 많이 투표 된 질문과 어떻게 다릅니 까? stackoverflow.com/a/804956/931303
Jorge Leitao

1
@ JorgeLeitão 당신은 그것이 어떻게 다른지 모르십니까? 한 줄로 표시하는 방법을 보여주지 않습니다.
Pavel P

17

C ++ (일반 C는 아님)에서 두 정의가 완전히 동일 하다면 유형을 두 번 typedef하는 것이 합법적입니다 .

// foo.h
struct A{};
typedef A *PA;

// bar.h
struct A;  // forward declare A
typedef A *PA;
void func(PA x);

// baz.cc
#include "bar.h"
#include "foo.h"
// We've now included the definition for PA twice, but it's ok since they're the same
...
A x;
func(&x);

34
유지 관리 아니요. 이런 종류의 일이 조만간 당신을 물고 있습니다.
Mark Storer

3
@MarkStorer, 적어도 컴파일러는 차이점을 발견하고 오류를 생성합니다. Visual C ++로 이것을 확인했습니다.
Alan

좋지만 정의에 의해 비어 A있기 때문에 어떻게 이런 식으로 필드를 A정의합니까?
Patrizio Bertoni

10

유형을 선언하기 때문에 크기를 알아야합니다. 형식에 대한 포인터를 전달하거나 형식에 대한 포인터를 typedef로 전달할 수 있습니다.

정말로 원한다면 pimpl 관용구를 사용하여 포함을 낮출 수 있습니다. 그러나 포인터가 아닌 형식을 사용하려면 컴파일러에서 크기를 알아야합니다.

편집 : j_random_hacker는이 답변에 중요한 자격을 추가합니다. 기본적으로 크기를 사용 하여 유형 을 사용해야 한다는 것을 알아야하지만 형식 이 존재 한다는 것을 알아야 할 경우 앞으로 선언을 할 수 있습니다 . 유형. OP는 코드를 표시하지 않았지만 컴파일하지 않을 것이라고 불평했기 때문에 OP가 유형을 참조 하려고하는 것이 아니라 유형 을 사용 하려고한다고 가정 했습니다.


35
글쎄, 클래스 타입의 순방향 선언은 크기에 대한 지식없이 이러한 타입을 선언합니다. 또한, 불완전한 유형에 대한 포인터 및 참조를 정의 할 수있을뿐만 아니라 매개 변수를 사용하거나 해당 유형의 값을 리턴하는 함수를 선언 할 수 있지만 정의 할 수는 없습니다.
j_random_hacker

3
나는 그것이 좋은 가정이라고 생각하지 않습니다. 이 대답은 요점 옆에 있습니다. 이것은 typedef 순방향 선언의 경우입니다.
Cookie

6

앞으로 선언을 사용 하는 대신 전체의 #include의하면 경우에만 수 없습니다 (이 파일의 범위) 유형 자체 만의 포인터 또는 참조를 사용하여 의도.

형식 자체를 사용하려면 컴파일러에서 크기를 알아야합니다. 따라서 전체 선언을보아야 #include합니다. 따라서 전체 가 필요합니다.

그러나 포인터 또는 참조의 크기는 포인트의 크기에 관계없이 컴파일러에 알려져 있으므로 정방향 선언으로 충분합니다. 형식 식별자 이름을 선언합니다.

흥미롭게도 포인터, 참조 class또는 struct유형을 사용할 때 컴파일러는 불완전한 유형을 처리 하여 포인트 유형을 전달할 필요가 없습니다.

// header.h

// Look Ma! No forward declarations!
typedef class A* APtr; // class A is an incomplete type - no fwd. decl. anywhere
typedef class A& ARef;

typedef struct B* BPtr; // struct B is an incomplete type - no fwd. decl. anywhere
typedef struct B& BRef;

// Using the name without the class/struct specifier requires fwd. decl. the type itself.    
class C;         // fwd. decl. type
typedef C* CPtr; // no class/struct specifier 
typedef C& CRef; // no class/struct specifier 

struct D;        // fwd. decl. type
typedef D* DPtr; // no class/struct specifier 
typedef D& DRef; // no class/struct specifier 

2

나는 같은 문제가 있었고 다른 파일의 여러 typedef를 엉망으로 만들고 싶지 않았으므로 상속으로 해결했습니다.

였다:

class BurstBoss {

public:

    typedef std::pair<Ogre::ParticleSystem*, bool> ParticleSystem; // removed this with...

했다 :

class ParticleSystem : public std::pair<Ogre::ParticleSystem*, bool>
{

public:

    ParticleSystem(Ogre::ParticleSystem* system, bool enabled) : std::pair<Ogre::ParticleSystem*, bool>(system, enabled) {
    };
};

매력처럼 일했다. 물론, 나는 모든 참조를 변경해야했다.

BurstBoss::ParticleSystem

단순히

ParticleSystem

1

나는 대체 typedef( using상속과 생성자 상속 될 특정)을 (?).

실물

using CallStack = std::array<StackFrame, MAX_CALLSTACK_DEPTH>;

대체

struct CallStack // Not a typedef to allow forward declaration.
  : public std::array<StackFrame, MAX_CALLSTACK_DEPTH>
{
  typedef std::array<StackFrame, MAX_CALLSTACK_DEPTH> Base;
  using Base::Base;
};

이렇게하면 CallStack다음과 같이 선언 할 수있었습니다 .

class CallStack;

0

Bill Kotsias가 지적했듯이 포인트의 typedef 세부 정보를 비공개로 유지하고 앞으로 선언하는 유일한 합리적인 방법은 상속입니다. C ++ 11로 조금 더 멋지게 할 수 있습니다. 이걸 고려하세요:

// LibraryPublicHeader.h

class Implementation;

class Library
{
...
private:
    Implementation* impl;
};
// LibraryPrivateImplementation.cpp

// This annoyingly does not work:
//
//     typedef std::shared_ptr<Foo> Implementation;

// However this does, and is almost as good.
class Implementation : public std::shared_ptr<Foo>
{
public:
    // C++11 allows us to easily copy all the constructors.
    using shared_ptr::shared_ptr;
};

0

@ BillKotsias와 마찬가지로 상속을 사용했으며 저에게 효과적이었습니다.

나는이 혼란을 바꿨다 (내 선언에 모든 ​​부스트 헤더가 필요하다 * .h)

#include <boost/accumulators/accumulators.hpp>
#include <boost/accumulators/statistics.hpp>
#include <boost/accumulators/statistics/stats.hpp>
#include <boost/accumulators/statistics/mean.hpp>
#include <boost/accumulators/statistics/moment.hpp>
#include <boost/accumulators/statistics/min.hpp>
#include <boost/accumulators/statistics/max.hpp>

typedef boost::accumulators::accumulator_set<float,
 boost::accumulators::features<
  boost::accumulators::tag::median,
  boost::accumulators::tag::mean,
  boost::accumulators::tag::min,
  boost::accumulators::tag::max
 >> VanillaAccumulator_t ;
std::unique_ptr<VanillaAccumulator_t> acc;

이 선언에 (* .h)

class VanillaAccumulator;
std::unique_ptr<VanillaAccumulator> acc;

구현 (* .cpp)은

#include <boost/accumulators/accumulators.hpp>
#include <boost/accumulators/statistics.hpp>
#include <boost/accumulators/statistics/stats.hpp>
#include <boost/accumulators/statistics/mean.hpp>
#include <boost/accumulators/statistics/moment.hpp>
#include <boost/accumulators/statistics/min.hpp>
#include <boost/accumulators/statistics/max.hpp>

class VanillaAccumulator : public
  boost::accumulators::accumulator_set<float,
    boost::accumulators::features<
      boost::accumulators::tag::median,
      boost::accumulators::tag::mean,
      boost::accumulators::tag::min,
      boost::accumulators::tag::max
>>
{
};
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.