Tại sao trình biên dịch không cho phép tôi chuyển tiếp khai báo một typedef?
Giả sử không thể, cách tốt nhất để giữ cho cây bao gồm của tôi nhỏ là gì?
Tại sao trình biên dịch không cho phép tôi chuyển tiếp khai báo một typedef?
Giả sử không thể, cách tốt nhất để giữ cho cây bao gồm của tôi nhỏ là gì?
Câu trả lời:
Bạn có thể làm typedef chuyển tiếp. Nhưng để làm
typedef A B;
trước tiên bạn phải chuyển tiếp tuyên bố A
:
class A;
typedef A B;
typedef
tên một loại mẫu đa cấp phức tạp sử dụng khai báo chuyển tiếp theo cách này thì khá phức tạp và khó khăn. Chưa kể rằng nó có thể yêu cầu đi sâu vào chi tiết triển khai ẩn trong các đối số mẫu mặc định. Và giải pháp cuối cùng là một mã dài và không thể đọc được (đặc biệt là khi các loại đến từ nhiều không gian tên khác nhau) rất dễ thay đổi trong loại ban đầu.
Đối với những người như tôi, những người đang muốn chuyển tiếp khai báo một cấu trúc kiểu C được xác định bằng cách sử dụng typedef, trong một số mã c ++, tôi đã tìm thấy một giải pháp như sau ...
// 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;
}
Để "fwd khai báo một typedef", bạn cần fwd khai báo một lớp hoặc một cấu trúc và sau đó bạn có thể gõ kiểu khai báo typedef. Nhiều typedefs giống nhau được chấp nhận bởi trình biên dịch.
dạng dài:
class MyClass;
typedef MyClass myclass_t;
hình thức ngắn:
typedef class MyClass myclass_t;
Trong C ++ (nhưng không đơn giản là C), việc nhập loại hai lần là hoàn toàn hợp pháp, miễn là cả hai định nghĩa hoàn toàn giống nhau:
// 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);
A
các trường theo cách này vì A
trống rỗng theo định nghĩa?
Bởi vì để khai báo một loại, kích thước của nó cần phải được biết. Bạn có thể chuyển tiếp khai báo một con trỏ tới kiểu hoặc gõ con trỏ vào kiểu.
Nếu bạn thực sự muốn, bạn có thể sử dụng thành ngữ pimpl để giữ cho bao gồm xuống. Nhưng nếu bạn muốn sử dụng một loại, thay vì một con trỏ, trình biên dịch phải biết kích thước của nó.
Chỉnh sửa: j_random_hacker bổ sung một phẩm chất quan trọng cho câu trả lời này, về cơ bản là kích thước cần phải biết để sử dụng loại, nhưng có thể thực hiện khai báo chuyển tiếp nếu chúng ta chỉ cần biết loại tồn tại , để tạo con trỏ hoặc tham chiếu đến kiểu. Vì OP không hiển thị mã, nhưng phàn nàn rằng nó sẽ không biên dịch, tôi giả định (có lẽ chính xác) rằng OP đang cố gắng sử dụng loại, không chỉ đề cập đến nó.
Chỉ có thể sử dụng khai báo chuyển tiếp thay vì đầy đủ #include
khi bạn không có ý định sử dụng chính loại đó (trong phạm vi của tệp này) mà là một con trỏ hoặc tham chiếu đến nó.
Để sử dụng chính kiểu đó, trình biên dịch phải biết kích thước của nó - do đó phải xem khai báo đầy đủ của nó - do đó cần phải có đầy đủ #include
.
Tuy nhiên, kích thước của một con trỏ hoặc tham chiếu được trình biên dịch biết, bất kể kích thước của con trỏ, vì vậy một khai báo chuyển tiếp là đủ - nó khai báo một tên định danh kiểu.
Thật thú vị, khi sử dụng con trỏ hoặc tham chiếu đến class
hoặc struct
các loại, trình biên dịch có thể xử lý các loại không hoàn chỉnh, tiết kiệm cho bạn nhu cầu chuyển tiếp khai báo các loại pointee:
// 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
Tôi có cùng một vấn đề, không muốn gây rối với nhiều typedefs trong các tệp khác nhau, vì vậy tôi đã giải quyết vấn đề đó bằng sự kế thừa:
là:
class BurstBoss {
public:
typedef std::pair<Ogre::ParticleSystem*, bool> ParticleSystem; // removed this with...
đã làm:
class ParticleSystem : public std::pair<Ogre::ParticleSystem*, bool>
{
public:
ParticleSystem(Ogre::ParticleSystem* system, bool enabled) : std::pair<Ogre::ParticleSystem*, bool>(system, enabled) {
};
};
Làm việc như người ở. Tất nhiên, tôi đã phải thay đổi bất kỳ tài liệu tham khảo nào từ
BurstBoss::ParticleSystem
chỉ đơn giản là
ParticleSystem
Tôi đã thay thế typedef
( using
để được cụ thể) bằng thừa kế và kế thừa hàm tạo (?).
Nguyên
using CallStack = std::array<StackFrame, MAX_CALLSTACK_DEPTH>;
Đã thay thế
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;
};
Bằng cách này, tôi đã có thể chuyển tiếp tuyên bố CallStack
với:
class CallStack;
Như Bill Kotsias đã lưu ý, cách hợp lý duy nhất để giữ các chi tiết typedef của điểm của bạn ở chế độ riêng tư và chuyển tiếp tuyên bố chúng là với sự kế thừa. Bạn có thể làm điều đó đẹp hơn một chút với C ++ 11. Xem xét điều này:
// 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;
};
Giống như @BillKotsias, tôi đã sử dụng tính kế thừa và nó hoạt động với tôi.
Tôi đã thay đổi mớ hỗn độn này (yêu cầu tất cả các tiêu đề tăng trong tuyên bố của tôi * .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;
vào tuyên bố này (* .h)
class VanillaAccumulator;
std::unique_ptr<VanillaAccumulator> acc;
và việc thực hiện (* .cpp) là
#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
>>
{
};