ทำไมคอมไพเลอร์ไม่ให้ฉันไปข้างหน้าเพื่อประกาศ typedef?
ถ้าเป็นไปไม่ได้แนวทางปฏิบัติที่ดีที่สุดในการทำให้ต้นไม้รวมของฉันเล็ก ๆ คืออะไร?
ทำไมคอมไพเลอร์ไม่ให้ฉันไปข้างหน้าเพื่อประกาศ typedef?
ถ้าเป็นไปไม่ได้แนวทางปฏิบัติที่ดีที่สุดในการทำให้ต้นไม้รวมของฉันเล็ก ๆ คืออะไร?
คำตอบ:
คุณสามารถพิมพ์ล่วงหน้าได้ แต่ต้องทำ
typedef A B;
ก่อนอื่นคุณต้องส่งต่อประกาศA
:
class A;
typedef A B;
typedef
ชื่อประเภทเทมเพลตหลายระดับที่ซับซ้อนโดยใช้การประกาศไปข้างหน้าด้วยวิธีนี้ค่อนข้างซับซ้อนและยาก ไม่ต้องพูดถึงว่ามันอาจต้องดำน้ำในรายละเอียดการใช้งานที่ซ่อนอยู่ในข้อโต้แย้งแม่แบบเริ่มต้น และทางออกสุดท้ายคือรหัสที่มีความยาวและไม่สามารถอ่านได้ (โดยเฉพาะเมื่อประเภทมาจากเนมสเปซต่างๆ) มีแนวโน้มที่จะเปลี่ยนแปลงในรูปแบบดั้งเดิม
สำหรับคนที่ชอบฉันที่กำลังมองไปข้างหน้าประกาศ C-style struct ที่กำหนดโดยใช้ 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;
}
หากต้องการ "fwd ประกาศ typedef" คุณต้อง fwd ประกาศคลาสหรือ struct จากนั้นคุณสามารถพิมพ์ typedef ประกาศได้ คอมไพเลอร์ตัวเดียวกันหลายตัวนั้นเป็นที่ยอมรับได้
แบบยาว:
class MyClass;
typedef MyClass myclass_t;
แบบสั้น:
typedef class MyClass myclass_t;
ใน C ++ (แต่ไม่ใช่ C ธรรมดา) การพิมพ์ประเภทสองครั้งถูกต้องตามกฎหมายตราบใดที่คำจำกัดความทั้งสองเหมือนกันหมด :
// 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
เขตข้อมูลด้วยวิธีนี้เนื่องจากA
ว่างตามคำจำกัดความอย่างไร
เนื่องจากต้องประกาศประเภทจึงจำเป็นต้องทราบขนาด คุณสามารถส่งต่อตัวชี้ไปยังประเภทหรือพิมพ์ตัวชี้ไปยังประเภท
หากคุณต้องการจริงๆคุณสามารถใช้ pimpl idiom เพื่อให้รวมลง แต่ถ้าคุณต้องการใช้ชนิดแทนที่จะเป็นตัวชี้คอมไพเลอร์จะต้องรู้ขนาดของมัน
แก้ไข: j_random_hacker เพิ่มคุณสมบัติที่สำคัญให้กับคำตอบนี้โดยทั่วไปแล้วขนาดจำเป็นต้องรู้ในการใช้งานประเภทนี้ แต่สามารถทำการประกาศล่วงหน้าได้หากเราต้องการทราบประเภทที่มีอยู่เท่านั้นเพื่อสร้างตัวชี้หรือการอ้างอิงถึง ชนิด เนื่องจาก OP ไม่ได้แสดงรหัส แต่บ่นว่ามันจะไม่คอมไพล์ฉันจึงสันนิษฐาน (อาจถูกต้อง) ว่า OP พยายามใช้งานประเภทนั้นไม่ใช่แค่อ้างถึง
การใช้การประกาศไปข้างหน้าแทนที่จะเป็นแบบเต็ม#include
จะทำได้ก็ต่อเมื่อคุณไม่ได้ตั้งใจจะใช้ตัวพิมพ์ (ในขอบเขตของไฟล์นี้) แต่เป็นตัวชี้หรือการอ้างอิง
ในการใช้ชนิดตัวแปลคอมไพเลอร์จะต้องรู้ขนาดของมัน - ด้วยเหตุนี้จึงต้องเห็นการประกาศอย่างเต็มรูปแบบ - จึง#include
จำเป็นต้อง ใช้แบบเต็ม
อย่างไรก็ตามขนาดของตัวชี้หรือการอ้างอิงเป็นที่ทราบกันโดยคอมไพเลอร์โดยไม่คำนึงถึงขนาดของ Pointee ดังนั้นการประกาศไปข้างหน้าก็เพียงพอแล้ว - มันประกาศชื่อตัวระบุชนิด
ที่น่าสนใจเมื่อใช้ตัวชี้หรือการอ้างอิงถึงclass
หรือstruct
ชนิดคอมไพเลอร์สามารถจัดการประเภทที่ไม่สมบูรณ์ซึ่งจะช่วยให้คุณไม่จำเป็นต้องส่งต่อชนิดของ 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
ฉันมีปัญหาเดียวกันไม่ต้องการยุ่งกับ typedefs หลายไฟล์ที่แตกต่างกันดังนั้นฉันแก้ไขมันด้วยการสืบทอด:
คือ:
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
ฉันแทนที่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;
ตามที่ 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;
};
เช่นเดียวกับ @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
>>
{
};