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.