Mengapa kompiler tidak membiarkan saya meneruskan menyatakan typedef?
Dengan asumsi itu tidak mungkin, apa praktik terbaik untuk menjaga pohon inklusi saya tetap kecil?
Mengapa kompiler tidak membiarkan saya meneruskan menyatakan typedef?
Dengan asumsi itu tidak mungkin, apa praktik terbaik untuk menjaga pohon inklusi saya tetap kecil?
Jawaban:
Anda dapat melakukan forward typedef. Tapi untuk dilakukan
typedef A B;
Anda harus terlebih dahulu menyatakan A
:
class A;
typedef A B;
typedef
nama tipe templat bertingkat kompleks menggunakan deklarasi maju cara ini agak rumit dan sulit. Belum lagi bahwa itu mungkin memerlukan menyelam ke detail implementasi yang disembunyikan dalam argumen template default. Dan solusi akhirnya adalah kode yang panjang dan tidak dapat dibaca (terutama ketika jenis berasal dari berbagai ruang nama) sangat rentan terhadap perubahan dalam jenis aslinya.
Bagi Anda seperti saya, yang ingin maju mendeklarasikan struct C-style yang didefinisikan menggunakan typedef, dalam beberapa kode c ++, saya telah menemukan solusi yang berjalan sebagai berikut ...
// 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;
}
Untuk "fwd mendeklarasikan typedef" Anda perlu fwd mendeklarasikan kelas atau struct dan kemudian Anda dapat mengetikkan typeed yang dideklarasikan. Beberapa typedef identik dapat diterima oleh kompiler.
bentuk panjang:
class MyClass;
typedef MyClass myclass_t;
bentuk pendek:
typedef class MyClass myclass_t;
Di C ++ (tapi bukan C biasa), sangat sah untuk mengetikkan tipe dua kali, asalkan kedua definisi benar - benar identik:
// 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
bidang dengan cara ini karena A
kosong menurut definisi?
Karena untuk mendeklarasikan suatu tipe, ukurannya perlu diketahui. Anda dapat meneruskan mendeklarasikan pointer ke tipe, atau mengetikkan pointer ke tipe.
Jika Anda benar-benar ingin, Anda dapat menggunakan idiom pimpl untuk menjaga agar menyertakan. Tetapi jika Anda ingin menggunakan tipe, daripada pointer, kompiler harus mengetahui ukurannya.
Sunting: j_random_hacker menambahkan kualifikasi penting untuk jawaban ini, pada dasarnya ukuran itu perlu diketahui untuk menggunakan tipe tersebut, tetapi deklarasi maju dapat dibuat jika kita hanya perlu mengetahui tipe yang ada , untuk membuat pointer atau referensi ke Tipe. Karena OP tidak menunjukkan kode, tetapi mengeluh itu tidak dapat dikompilasi, saya berasumsi (mungkin dengan benar) bahwa OP sedang mencoba menggunakan tipe tersebut, tidak hanya merujuknya.
Menggunakan penerusan deklarasi alih - alih#include
s penuh hanya dimungkinkan bila Anda tidak bermaksud menggunakan tipe itu sendiri (dalam cakupan file ini) tetapi sebuah pointer atau referensi untuk itu.
Untuk menggunakan tipe itu sendiri, kompiler harus mengetahui ukurannya - maka deklarasi lengkapnya harus dilihat - maka diperlukan penuh #include
.
Namun, ukuran pointer atau referensi diketahui oleh kompiler, terlepas dari ukuran pointee, sehingga pernyataan maju sudah cukup - itu menyatakan nama pengenal jenis.
Menariknya, ketika menggunakan pointer atau referensi class
atau struct
tipe, kompiler dapat menangani tipe yang tidak lengkap sehingga Anda tidak perlu meneruskan menyatakan tipe pointee juga:
// 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
Saya memiliki masalah yang sama, tidak ingin dipusingkan dengan beberapa typedef dalam file yang berbeda, jadi saya menyelesaikannya dengan warisan:
dulu:
class BurstBoss {
public:
typedef std::pair<Ogre::ParticleSystem*, bool> ParticleSystem; // removed this with...
melakukan:
class ParticleSystem : public std::pair<Ogre::ParticleSystem*, bool>
{
public:
ParticleSystem(Ogre::ParticleSystem* system, bool enabled) : std::pair<Ogre::ParticleSystem*, bool>(system, enabled) {
};
};
Bekerja seperti pesona. Tentu saja, saya harus mengubah referensi apa pun dari
BurstBoss::ParticleSystem
untuk sederhana
ParticleSystem
Saya mengganti typedef
( using
lebih spesifik) dengan warisan dan konstruktor (?).
Asli
using CallStack = std::array<StackFrame, MAX_CALLSTACK_DEPTH>;
Diganti
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;
};
Dengan cara ini saya bisa maju menyatakan CallStack
dengan:
class CallStack;
Seperti yang dicatat oleh Bill Kotsias, satu-satunya cara yang masuk akal untuk menjaga detail typedef poin Anda tetap pribadi, dan meneruskannya adalah dengan warisan. Anda dapat melakukannya sedikit lebih baik dengan C ++ 11 sekalipun. Pertimbangkan ini:
// 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;
};
Seperti @BillKotsias, saya menggunakan warisan, dan itu berhasil untuk saya.
Saya mengubah kekacauan ini (yang mengharuskan semua tajuk boost dalam deklarasi saya * .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;
dalam deklarasi ini (* .h)
class VanillaAccumulator;
std::unique_ptr<VanillaAccumulator> acc;
dan implementasinya (* .cpp) tadinya
#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
>>
{
};