সি ++ এ টাইপয়েফের ফরোয়ার্ড ঘোষণা


235

সংকলক আমাকে কেন টাইপয়েফ ঘোষণা করতে দেবে না?

এটা অসম্ভব বলে ধরে নিই, আমার অন্তর্ভুক্তি গাছকে ছোট রাখার জন্য সেরা অনুশীলন কোনটি?

উত্তর:


170

আপনি ফরোয়ার্ড টাইপফ করতে পারেন। তবে করণীয়

typedef A B;

আপনাকে অবশ্যই আগে ঘোষণা করতে হবে A:

class A;

typedef A B;

11
+1 শেষ পর্যন্ত কারণ আপনি যখন প্রযুক্তিগতভাবে "ফরোয়ার্ড-টাইপদেফ" করতে পারবেন না (যেমন আপনি "টাইপডেফ এ;" লিখতে পারবেন না), আপনি ওপি আপনার ট্রিকটি ব্যবহার করে যা করতে চান তা প্রায় অবশ্যই সম্পাদন করতে পারবেন।
j_random_hacker

9
তবে সচেতন হোন, যদি টাইপিডেফ পরিবর্তন হয় আপনি সেই সমস্ত ফরোয়ার্ড ঘোষণাপত্রও বদলে দিতে পারেন, যা আপনি যদি পুরানো এবং নতুন টাইপডেফ একই ইন্টারফেসের সাথে প্রকারগুলি ব্যবহার করে থাকেন তবে আপনি মিস করতে পারেন।
গণিত

50
সাধারণভাবে এটি কার্যকর সমাধান নয়। উদাহরণস্বরূপ, যদি typedefনামগুলি একটি জটিল মাল্টিলেভেল টেম্পলেট প্রকারের জন্য এইভাবে একটি ফরোয়ার্ড ডিক্লেয়ারেশন ব্যবহার করে তবে এটি জটিল এবং কঠিন। এটির জন্য এটি ডিফল্ট টেম্পলেট আর্গুমেন্টে লুকিয়ে থাকা প্রয়োগের বিশদগুলিতে ডাইভিংয়ের প্রয়োজন হতে পারে তা উল্লেখ করার দরকার নেই। এবং শেষের সমাধানটি একটি দীর্ঘ এবং অপঠনযোগ্য কোড (বিশেষত যখন প্রকারগুলি বিভিন্ন নেমস্পেস থেকে আসে) আসল প্রকারে পরিবর্তিত হয় one
আদম বদুরা

3
এছাড়াও এটি "বাস্তবায়ন বিশদগুলি" দেখায় (যদিও পুরোপুরি না হলেও এখনও ...) তবে ভবিষ্যতে ঘোষণার পিছনে ধারণাটি তাদের আড়াল করা ছিল।
আদম বদুরা

3
@ উইন্ডফাইন্ডার: এটি করে: টেমপ্লেট <ক্লাস টি> ক্লাস এ; টাইপডেফ এ <সি> বি;
মিলিয়ান

47

আমার মতো আপনারা যারা, সি-স্টাইলের কাঠামো ঘোষণা করতে চেয়েছেন যা টাইপেইফ ব্যবহার করে সংজ্ঞায়িত হয়েছিল, কিছু সি ++ কোডে, আমি একটি সমাধান পেয়েছি যা নিম্নলিখিত হিসাবে চলে ...

// 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
@ লিটল জন এই সমাধানটির সাথে সমস্যাটি হ'ল ডামি নাম _বাহ পাবলিক এপিআইয়ের অংশ হিসাবে বিবেচিত হয় না। এগিয়ে ডেল কেয়ার ফাইল দেখুন।
ব্যবহারকারীর 877329

23

"Fwd একটি typedef ডিক্লেয়ার" করতে আপনার fwd একটি ক্লাস বা স্ট্রাক্ট ঘোষণা করতে হবে এবং তারপরে আপনি টাইপডেফ ঘোষিত টাইপটি টাইপ করতে পারেন। একাধিক অভিন্ন টাইডিডেফ সংকলক দ্বারা গ্রহণযোগ্য।

দীর্ঘ ফর্ম:

class MyClass;
typedef MyClass myclass_t;

সংক্ষিপ্ত রূপ:

typedef class MyClass myclass_t;

এটি কীভাবে সর্বাধিক ভোটিত প্রশ্ন থেকে আলাদা? stackoverflow.com/a/804956/931303
জর্জি লিটাও

1
@ জর্জিলেট আপনি কি দেখছেন না যে এটির চেয়ে আলাদা? এটি এক লাইনে কীভাবে করা যায় তা দেখায় না।
পাভেল পি

17

সি ++ তে (তবে প্লেইন সি নয়), দু'বার সংজ্ঞা সম্পূর্ণরূপে অদৃশ্য হওয়া পর্যন্ত দু'বার টাইপ টাইপ করা পুরোপুরি আইনী :

// 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
রক্ষণাবেক্ষণ নং নয় এই ধরণের জিনিসটি আপনাকে শীঘ্রই বা পরে কীবোর্ডে কাটবে।
মার্ক স্টোর

3
@ মার্কস্টোরার, কমপক্ষে সংকলক যে কোনও পার্থক্য ধরবে এবং একটি ত্রুটি তৈরি করবে। আমি ভিজ্যুয়াল সি ++ দিয়ে এটি যাচাই করেছি।
অ্যালান

দুর্দান্ত, তবে সংজ্ঞা অনুসারে খালি হওয়ায় আপনি Aক্ষেত্রগুলি এভাবে কীভাবে সংজ্ঞায়িত করবেন A?
প্যাট্রিজিও বার্তোনি

10

কোনও প্রকার ঘোষণা করার জন্য, এর আকারটি জানা দরকার। আপনি টাইপটির জন্য একটি পয়েন্টার ঘোষণা করতে পারেন, বা টাইপফোন টাইপ করতে একটি পয়েন্টার।

আপনি যদি সত্যিই চান, তবে এইগুলি নীচে রাখার জন্য আপনি পিম্পল আইডিয়ামটি ব্যবহার করতে পারেন। তবে আপনি যদি পয়েন্টারের পরিবর্তে কোনও প্রকার ব্যবহার করতে চান তবে সংকলকটির আকারটি জানতে হবে।

সম্পাদনা করুন: j_random_hacker এই উত্তরের জন্য একটি গুরুত্বপূর্ণ যোগ্যতা যুক্ত করেছে, মূলত এই ধরণেরটি ব্যবহার করতে আকারের জানা প্রয়োজন , তবে পয়েন্টার বা রেফারেন্স তৈরি করার জন্য আমাদের কেবল ধরণের উপস্থিতি জানতে হবে তবে একটি অগ্রণী ঘোষণা করা যেতে পারে টাইপ করুন। যেহেতু ওপি কোডটি প্রদর্শন করে না, তবে এটি সংকলন করবে না বলে অভিযোগ করেছে, আমি ধরে নিয়েছি (সম্ভবত সঠিকভাবে) যে ওপি টাইপটি ব্যবহার করার চেষ্টা করছে , কেবল এটি উল্লেখ করা হয়নি।


35
ঠিক আছে, শ্রেণীর ধরণের ফরোয়ার্ড ঘোষণাপত্রগুলি তাদের আকারের অজান্তে এই ধরণের ঘোষণা করে। এছাড়াও, এই জাতীয় অসম্পূর্ণ প্রকারের জন্য পয়েন্টার এবং রেফারেন্স সংজ্ঞায়িত করতে সক্ষম হওয়া ছাড়াও ফাংশনগুলি ঘোষিত হতে পারে (তবে সংজ্ঞায়িত নয়) যা পরামিতি নেয় এবং / অথবা এই জাতীয় ধরণের মান ফেরত দেয়।
j_random_hacker

3
দুঃখিত, আমি এটি একটি ভাল ধারণা বলে মনে করি না। এই উত্তরটি বিন্দুর পাশে রয়েছে। এটি টাইডেফের ক্ষেত্রে একটি ফরোয়ার্ড ডিক্লেয়ারেশন।
কুকি

6

পূর্ণাঙ্গের পরিবর্তে ফরোয়ার্ড ডিক্লেয়ারেশনগুলি ব্যবহার করা #includeকেবল তখনই সম্ভব যখন আপনি প্রকারটি (এই ফাইলের স্কোপে) নিজেই ব্যবহার করতে চাইছেন না তবে এটির পয়েন্টার বা রেফারেন্স রয়েছে।

টাইপটি নিজেই ব্যবহার করতে, সংকলকটির অবশ্যই তার আকার অবশ্যই জানতে হবে - সুতরাং এর সম্পূর্ণ ঘোষণাটি অবশ্যই দেখতে হবে - সুতরাং একটি পূর্ণ #includeপ্রয়োজন।

যাইহোক, পয়েন্টার আকার বা রেফারেন্সের আকারটি পয়েন্টটির আকার নির্বিশেষে সংকলকটির কাছে জানা যায়, সুতরাং একটি অগ্রণী ঘোষণা যথেষ্ট - এটি কোনও ধরণের সনাক্তকারী নাম ঘোষণা করে।

মজার ব্যাপার হচ্ছে, যখন পয়েন্টার বা রেফারেন্স ব্যবহার 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 

2

আমার একই সমস্যা ছিল, বিভিন্ন ফাইলে একাধিক টাইপেডেফের সাথে গোলযোগ করতে চাই না, তাই উত্তরাধিকারের সাথে সমাধান করেছি:

ছিল:

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

যেমন বিল কোটসিয়াস উল্লেখ করেছেন, আপনার পয়েন্টের টাইপিডেফের বিবরণ ব্যক্তিগত রাখার এবং সেগুলি ঘোষণা করার একমাত্র যুক্তিযুক্ত উপায় হ'ল উত্তরাধিকার সহ। আপনি যদিও এটি সি ++ 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

@ বিলকোটেসিয়াসের মতো আমি উত্তরাধিকার ব্যবহার করেছি এবং এটি আমার পক্ষে কাজ করেছে।

আমি এই জগাখিচুড়ি পরিবর্তন করেছি (যার জন্য আমার ঘোষণার সমস্ত উত্সাহী শিরোনাম প্রয়োজন *। এইচ)

#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.