“सदस्य * :: * वर्ग डेटा सदस्य को इंगित करें


242

मुझे यह अजीब कोड स्निपेट आया, जो ठीक संकलन करता है:

class Car
{
    public:
    int speed;
};

int main()
{
    int Car::*pSpeed = &Car::speed;
    return 0;
}

C ++ में किसी कक्षा के गैर-स्थैतिक डेटा सदस्य के लिए यह सूचक क्यों है? वास्तविक कोड में इस अजीब सूचक का उपयोग क्या है?


यहाँ मैं इसे कहाँ पाया, मुझे भी भ्रमित किया ... लेकिन अब समझ में आता है: stackoverflow.com/a/982941/211160
HostileFork का कहना है कि SE

जवाबों:


189

यह "सदस्य के लिए सूचक" है - निम्न कोड इसके उपयोग को दिखाता है:

#include <iostream>
using namespace std;

class Car
{
    public:
    int speed;
};

int main()
{
    int Car::*pSpeed = &Car::speed;

    Car c1;
    c1.speed = 1;       // direct access
    cout << "speed is " << c1.speed << endl;
    c1.*pSpeed = 2;     // access via pointer to member
    cout << "speed is " << c1.speed << endl;
    return 0;
}

जैसा कि आप ऐसा क्यों करना चाहते हैं, यह अच्छी तरह से आपको अप्रत्यक्ष स्तर देता है जो कुछ मुश्किल समस्याओं को हल कर सकता है। लेकिन ईमानदार होने के लिए, मुझे कभी भी उन्हें अपने कोड में उपयोग नहीं करना पड़ा।

संपादित करें: मैं सदस्य डेटा के संकेत के लिए एक ठोस उपयोग के बारे में नहीं सोच सकता। प्वाइंटर टू मेम्बर फ़ंक्शंस का उपयोग प्लगेबल आर्किटेक्चर में किया जा सकता है, लेकिन एक बार फिर से एक छोटी सी जगह में एक उदाहरण प्रस्तुत करना मुझे हरा देता है। निम्नलिखित मेरा सबसे अच्छा (अप्रकाशित) प्रयास है - एक ऐसा फ़ंक्शन लागू करें जो उपयोगकर्ता-चयनित सदस्य फ़ंक्शन को ऑब्जेक्ट पर लागू करने से पहले कुछ पूर्व और पोस्ट प्रोसेसिंग करेगा:

void Apply( SomeClass * c, void (SomeClass::*func)() ) {
    // do hefty pre-call processing
    (c->*func)();  // call user specified function
    // do hefty post-call processing
}

चारों ओर कोष्ठक c->*funcआवश्यक हैं क्योंकि ->*ऑपरेटर को फ़ंक्शन कॉल ऑपरेटर की तुलना में कम पूर्वता है।


3
क्या आप एक मुश्किल स्थिति का उदाहरण दिखा सकते हैं जहाँ यह उपयोगी है? धन्यवाद।
अश्विन नांजप्पा

मेरे पास एक अन्य SO उत्तर में Traits वर्ग में सूचक-से-सदस्य का उपयोग करने का एक उदाहरण है ।
माइक डेनिमोन

एक उदाहरण कुछ घटना-आधारित प्रणाली के लिए "कॉलबैक"-टाइप कक्षा लिख ​​रहा है। उदाहरण के लिए, CEGUI का UI ईवेंट सब्सक्रिप्शन सिस्टम, एक टेम्पर्ड कॉलबैक लेता है जो आपके चयन के सदस्य फ़ंक्शन के लिए एक पॉइंटर को स्टोर करता है, ताकि आप ईवेंट को संभालने के लिए एक विधि निर्दिष्ट कर सकें।
बेंजी XVI

2
इस कोड में टेम्पलेट फ़ंक्शन में पॉइंटर-टू- डेटा -member उपयोग का एक बहुत अच्छा उदाहरण है
alveko

3
मैंने हाल ही में क्रमांकन ढांचे में डेटा सदस्यों के लिए पॉइंटर्स का उपयोग किया है। स्टेटिक मार्शेलर ऑब्जेक्ट को क्रमिक डेटा सदस्यों को पॉइंटर रखने वाले रैपर की सूची के साथ आरंभीकृत किया गया था। इस कोड का एक प्रारंभिक प्रोटोटाइप।
अलेक्सी बिरुकोव

79

यह सबसे सरल उदाहरण है जिसके बारे में मैं सोच सकता हूं कि यह उन दुर्लभ मामलों का खुलासा करता है जहां यह सुविधा प्रासंगिक है:

#include <iostream>

class bowl {
public:
    int apples;
    int oranges;
};

int count_fruit(bowl * begin, bowl * end, int bowl::*fruit)
{
    int count = 0;
    for (bowl * iterator = begin; iterator != end; ++ iterator)
        count += iterator->*fruit;
    return count;
}

int main()
{
    bowl bowls[2] = {
        { 1, 2 },
        { 3, 5 }
    };
    std::cout << "I have " << count_fruit(bowls, bowls + 2, & bowl::apples) << " apples\n";
    std::cout << "I have " << count_fruit(bowls, bowls + 2, & bowl::oranges) << " oranges\n";
    return 0;
}

यहाँ ध्यान देने वाली बात यह है कि count काउंट करने के लिए पॉइंटर पास किया गया है। यह आपको अलग-अलग count_apples और count_oranges फ़ंक्शन लिखने के लिए बचाता है।


3
यह नहीं होना चाहिए &bowls.applesऔर &bowls.oranges? &bowl::applesऔर &bowl::orangesकिसी बात की ओर इशारा नहीं करता।
डैन निसेनबाम

19
&bowl::applesऔर &bowl::orangesकिसी वस्तु के सदस्यों को इंगित न करें ; वे एक वर्ग के सदस्यों को इंगित करते हैं । इससे पहले कि वे कुछ इंगित करें, उन्हें एक संकेतक के साथ एक वास्तविक वस्तु के साथ जोड़ा जाना चाहिए। उस संयोजन को ->*ऑपरेटर के साथ हासिल किया जाता है ।
जॉन मैक्फर्लेन 20

58

एक और आवेदन घुसपैठ की सूची है। तत्व प्रकार सूची को बता सकता है कि इसके अगले / प्रचलित संकेत क्या हैं। इसलिए सूची हार्ड-कोडेड नामों का उपयोग नहीं करती है, लेकिन फिर भी मौजूदा पॉइंटर्स का उपयोग कर सकती है:

// say this is some existing structure. And we want to use
// a list. We can tell it that the next pointer
// is apple::next.
struct apple {
    int data;
    apple * next;
};

// simple example of a minimal intrusive list. Could specify the
// member pointer as template argument too, if we wanted:
// template<typename E, E *E::*next_ptr>
template<typename E>
struct List {
    List(E *E::*next_ptr):head(0), next_ptr(next_ptr) { }

    void add(E &e) {
        // access its next pointer by the member pointer
        e.*next_ptr = head;
        head = &e;
    }

    E * head;
    E *E::*next_ptr;
};

int main() {
    List<apple> lst(&apple::next);

    apple a;
    lst.add(a);
}

यदि यह वास्तव में एक लिंक की गई सूची है, तो आप ऐसा कुछ नहीं चाहेंगे: शून्य जोड़ें (E * e) {e -> * next_pte = head; सिर = ई; } ??
eeeeaaii

4
@ मैं आपको संदर्भ मापदंडों के बारे में पढ़ने की सलाह देता हूं। मैंने जो किया वह मूल रूप से आपने जो किया उसके बराबर है।
जोहान्स शाउब -

आपके कोड उदाहरण के लिए +1, लेकिन मैंने पॉइंटर-टू-मेंबर, किसी अन्य उदाहरण के उपयोग के लिए कोई आवश्यकता नहीं देखी?
अल्कोट

3
@ अलॉट: आप इसे अन्य लिंक्ड-लिस्ट जैसी संरचनाओं पर लागू कर सकते हैं जहां अगले पॉइंटर का नाम नहीं है next
icktoofay

41

यहाँ एक वास्तविक दुनिया उदाहरण है जो मैं अभी सिग्नल प्रोसेसिंग / नियंत्रण प्रणाली से काम कर रहा हूँ:

मान लीजिए कि आपके पास कुछ संरचना है जो आपके द्वारा एकत्रित किए जा रहे डेटा का प्रतिनिधित्व करती है:

struct Sample {
    time_t time;
    double value1;
    double value2;
    double value3;
};

अब मान लीजिए कि आप उन्हें एक वेक्टर में भर देते हैं:

std::vector<Sample> samples;
... fill the vector ...

अब मान लीजिए कि आप किसी एक नमूने पर कई प्रकार के चरों में से कुछ फ़ंक्शन (माध्य का मतलब) की गणना करना चाहते हैं, और आप इस माध्य गणना को एक फंक्शन में बदलना चाहते हैं। सूचक-सदस्य इसे आसान बनाता है:

double Mean(std::vector<Sample>::const_iterator begin, 
    std::vector<Sample>::const_iterator end,
    double Sample::* var)
{
    float mean = 0;
    int samples = 0;
    for(; begin != end; begin++) {
        const Sample& s = *begin;
        mean += s.*var;
        samples++;
    }
    mean /= samples;
    return mean;
}

...
double mean = Mean(samples.begin(), samples.end(), &Sample::value2);

नोट अधिक संक्षिप्त टेम्पलेट-फ़ंक्शन दृष्टिकोण के लिए 2016/08/05 को संपादित किया गया

और, ज़ाहिर है, आप इसे किसी भी फॉरवर्ड-इटरेटर और किसी भी प्रकार के मान के लिए गणना करने के लिए टेम्पलेट कर सकते हैं जो size_t द्वारा खुद के साथ और विभाजन का समर्थन करता है:

template<typename Titer, typename S>
S mean(Titer begin, const Titer& end, S std::iterator_traits<Titer>::value_type::* var) {
    using T = typename std::iterator_traits<Titer>::value_type;
    S sum = 0;
    size_t samples = 0;
    for( ; begin != end ; ++begin ) {
        const T& s = *begin;
        sum += s.*var;
        samples++;
    }
    return sum / samples;
}

struct Sample {
    double x;
}

std::vector<Sample> samples { {1.0}, {2.0}, {3.0} };
double m = mean(samples.begin(), samples.end(), &Sample::x);

EDIT - उपरोक्त कोड में प्रदर्शन निहितार्थ हैं

आपको ध्यान देना चाहिए, जैसा कि मैंने जल्द ही पता चला है, कि ऊपर दिए गए कोड में कुछ गंभीर प्रदर्शन निहितार्थ हैं। सारांश यह है कि यदि आप किसी टाइम सीरीज़ पर सारांश आँकड़ा की गणना कर रहे हैं, या एफएफटी आदि की गणना कर रहे हैं, तो आपको प्रत्येक चर के लिए मूल्यों को स्मृति में संचित करना चाहिए। अन्यथा, श्रृंखला पर पुनरावृत्ति करने से पुनर्प्राप्त किए गए प्रत्येक मूल्य के लिए कैश मिस हो जाएगा।

इस कोड के प्रदर्शन पर विचार करें:

struct Sample {
  float w, x, y, z;
};

std::vector<Sample> series = ...;

float sum = 0;
int samples = 0;
for(auto it = series.begin(); it != series.end(); it++) {
  sum += *it.x;
  samples++;
}
float mean = sum / samples;

कई आर्किटेक्चर पर, एक उदाहरण Sampleकैश लाइन को भरेगा। तो लूप के प्रत्येक पुनरावृत्ति पर, एक नमूना को मेमोरी से कैश में खींच लिया जाएगा। कैश लाइन से 4 बाइट का उपयोग किया जाएगा और बाकी को फेंक दिया जाएगा, और अगले पुनरावृत्ति के परिणामस्वरूप एक और कैश मिस, मेमोरी एक्सेस और इसी तरह होगा।

ऐसा करने के लिए बहुत बेहतर:

struct Samples {
  std::vector<float> w, x, y, z;
};

Samples series = ...;

float sum = 0;
float samples = 0;
for(auto it = series.x.begin(); it != series.x.end(); it++) {
  sum += *it;
  samples++;
}
float mean = sum / samples;

अब जब पहले x मान को मेमोरी से लोड किया जाता है, तो अगले तीन को भी कैश में लोड किया जाएगा (उपयुक्त संरेखण को दबाते हुए), जिसका अर्थ है कि आपको अगले तीन पुनरावृत्तियों के लिए लोड किए गए किसी भी मान की आवश्यकता नहीं है।

उपरोक्त SSE2 आर्किटेक्चर पर SIMD निर्देशों के उपयोग के माध्यम से उपरोक्त एल्गोरिथ्म में कुछ हद तक सुधार किया जा सकता है। हालाँकि, ये बहुत बेहतर काम करते हैं यदि मान सभी मेमोरी में सन्निहित हैं और आप चार नमूनों को एक साथ लोड करने के लिए एक एकल निर्देश का उपयोग कर सकते हैं (अधिक बाद में एसएसई संस्करण)।

YMMV - अपने एल्गोरिथ्म के अनुरूप अपने डेटा संरचनाओं को डिज़ाइन करें।


यह उत्कृष्ट है। मैं कुछ बहुत समान लागू करने वाला हूं, और अब मुझे अजीब वाक्य रचना का पता लगाने की जरूरत नहीं है! धन्यवाद!
निकु स्तिर्का

यह सबसे अच्छा जवाब है। double Sample::*भाग कुंजी है!
इल

37

आप बाद में किसी भी उदाहरण पर इस सदस्य तक पहुँच सकते हैं :

int main()
{    
  int Car::*pSpeed = &Car::speed;    
  Car myCar;
  Car yourCar;

  int mySpeed = myCar.*pSpeed;
  int yourSpeed = yourCar.*pSpeed;

  assert(mySpeed > yourSpeed); // ;-)

  return 0;
}

ध्यान दें कि आपको इसे कॉल करने के लिए एक उदाहरण की आवश्यकता है, इसलिए यह एक प्रतिनिधि की तरह काम नहीं करता है।
इसका उपयोग शायद ही कभी किया जाता है, मुझे अपने सभी वर्षों में एक या दो बार इसकी आवश्यकता होती है।

सामान्य रूप से इंटरफ़ेस का उपयोग करना (यानी C ++ में शुद्ध आधार वर्ग) बेहतर डिज़ाइन विकल्प है।


लेकिन निश्चित रूप से यह सिर्फ बुरा अभ्यास है? youcar.setspeed (mycar.getpspeed) की तरह कुछ करना चाहिए
thecoshman

9
@thecoshman: पूरी तरह से निर्भर करता है - सेट / पाने के तरीकों के पीछे डेटा सदस्यों को छिपाना एनकैप्सुलेशन नहीं है और इंटरफेस एब्स्ट्रक्शन में केवल एक मिल्कमेड्स का प्रयास है। कई परिदृश्यों में, सार्वजनिक सदस्यों के लिए "विकृति" एक उचित विकल्प है। लेकिन यह चर्चा संभवतः टिप्पणी की कार्यक्षमता की सीमा से अधिक है।
peterchen

4
+1 को इंगित करने के लिए, अगर मैं सही ढंग से समझता हूं, कि यह किसी भी उदाहरण के सदस्य के लिए एक संकेतक है, और एक सूचक को एक उदाहरण के विशिष्ट मूल्य के लिए नहीं, जो कि वह हिस्सा है जो मैं पूरी तरह से गायब था।
जॉन्बेकर्स

@ फेलोशी आप सही ढंग से समझ रहे हैं :) (जवाब में इस पर जोर दिया)।
पेटेरचेन

26

आईबीएम पास इसके उपयोग के बारे में कुछ और दस्तावेज हैं। संक्षेप में, आप पॉइंटर को कक्षा में एक ऑफसेट के रूप में उपयोग कर रहे हैं। आप इन बिंदुओं का उपयोग उस कक्षा से अलग नहीं कर सकते हैं जिसका वे उल्लेख करते हैं, इसलिए:

  int Car::*pSpeed = &Car::speed;
  Car mycar;
  mycar.*pSpeed = 65;

यह थोड़ा अस्पष्ट लगता है, लेकिन एक संभावित अनुप्रयोग यह है कि यदि आप कई अलग-अलग ऑब्जेक्ट प्रकारों में जेनेरिक डेटा को डिसेर्बलाइज़ करने के लिए कोड लिखने का प्रयास कर रहे हैं, और आपके कोड को ऑब्जेक्ट प्रकारों को संभालने की आवश्यकता है, जिसके बारे में यह पूरी तरह से कुछ भी नहीं जानता है (उदाहरण के लिए, आपका कोड है एक पुस्तकालय में, और जिन वस्तुओं में आप अपने पुस्तकालय के एक उपयोगकर्ता द्वारा निर्मित किए गए हैं)। सदस्य पॉइंटर्स आपको व्यक्तिगत डेटा सदस्य ऑफ़सेट्स का संदर्भ देने का एक सामान्य, अर्ध-सुपाठ्य तरीका देते हैं, बिना टाइप किए शून्य का सहारा लेने के लिए * जिस तरह से आप सी संरचनाओं के लिए कर सकते हैं।


क्या आप एक कोड स्निपेट उदाहरण साझा कर सकते हैं जहां यह निर्माण उपयोगी है? धन्यवाद।
अश्विन नांजप्पा

2
मैं वर्तमान में कुछ DCOM कार्य करने और प्रबंधित संसाधन कक्षाओं का उपयोग करने के कारण ऐसा कर रहा हूं, जिसमें प्रत्येक कॉल से पहले थोड़ा सा काम करना शामिल है, और com, प्लस टेंपलेटिंग को भेजने के लिए आंतरिक प्रतिनिधित्व के लिए डेटा सदस्यों का उपयोग करना, बहुत कुछ करता है बॉयलर प्लेट कोड बहुत छोटा है
Dan

19

यह एक समान तरीके से सदस्य चर और कार्यों को बांधना संभव बनाता है। निम्नलिखित आपके कार वर्ग के साथ उदाहरण है। अधिक आम उपयोग बाध्यकारी होगा std::pair::firstऔर ::secondजब एसटीएल एल्गोरिदम और एक नक्शे पर बूस्ट में इस्तेमाल करते हैं।

#include <list>
#include <algorithm>
#include <iostream>
#include <iterator>
#include <boost/lambda/lambda.hpp>
#include <boost/lambda/bind.hpp>


class Car {
public:
    Car(int s): speed(s) {}
    void drive() {
        std::cout << "Driving at " << speed << " km/h" << std::endl;
    }
    int speed;
};

int main() {

    using namespace std;
    using namespace boost::lambda;

    list<Car> l;
    l.push_back(Car(10));
    l.push_back(Car(140));
    l.push_back(Car(130));
    l.push_back(Car(60));

    // Speeding cars
    list<Car> s;

    // Binding a value to a member variable.
    // Find all cars with speed over 60 km/h.
    remove_copy_if(l.begin(), l.end(),
                   back_inserter(s),
                   bind(&Car::speed, _1) <= 60);

    // Binding a value to a member function.
    // Call a function on each car.
    for_each(s.begin(), s.end(), bind(&Car::drive, _1));

    return 0;
}

11

आप एक दोहरे, नाम-सदस्य (iexdata) और सरणी-सबस्क्रिप्ट (यानी x [आईडीएक्स]) इंटरफ़ेस को सक्षम करने के लिए (समरूप) सदस्य डेटा के लिए सूचक की एक सरणी का उपयोग कर सकते हैं।

#include <cassert>
#include <cstddef>

struct vector3 {
    float x;
    float y;
    float z;

    float& operator[](std::size_t idx) {
        static float vector3::*component[3] = {
            &vector3::x, &vector3::y, &vector3::z
        };
        return this->*component[idx];
    }
};

int main()
{
    vector3 v = { 0.0f, 1.0f, 2.0f };

    assert(&v[0] == &v.x);
    assert(&v[1] == &v.y);
    assert(&v[2] == &v.z);

    for (std::size_t i = 0; i < 3; ++i) {
        v[i] += 1.0f;
    }

    assert(v.x == 1.0f);
    assert(v.y == 2.0f);
    assert(v.z == 3.0f);

    return 0;
}

मैंने अधिक बार इसे एक अनाम फ़ील्ड v [3] सहित एक अनाम संघ का उपयोग करते हुए देखा है क्योंकि यह एक अप्रत्यक्ष, लेकिन फिर भी होशियारी से बचा जाता है, और गैर-सन्निहित क्षेत्रों के लिए संभवतः उपयोगी है।
ड्वेन रॉबिन्सन

2
@ ड्वेनरॉबिनसन लेकिन unionउस फैशन में टाइप-से-वाक्य का उपयोग करना मानक द्वारा अनुमति नहीं है क्योंकि यह अपरिभाषित व्यवहार के कई रूपों को आमंत्रित करता है ... जबकि यह उत्तर ठीक है।
अंडरस्कोर_ड

यह एक साफ उदाहरण है, लेकिन ऑपरेटर [] को पॉइंटर-टू-कंपोनेंट के बिना फिर से लिखा जा सकता है: float *component[] = { &x, &y, &z }; return *component[idx];यानी, पॉइंटर-टू-कंपोनेंट ऑब्सफैक्शन के अलावा कोई उद्देश्य नहीं देता है।
tobi_s

2

एक तरह से मैंने इसका इस्तेमाल किया है अगर मेरे पास एक कक्षा में कुछ करने के लिए दो कार्यान्वयन हैं और मैं एक रन स्टेट-टाइम में से एक को चुनना चाहता हूं, तो बिना किसी बयान के लगातार चलना होगा।

class Algorithm
{
public:
    Algorithm() : m_impFn( &Algorithm::implementationA ) {}
    void frequentlyCalled()
    {
        // Avoid if ( using A ) else if ( using B ) type of thing
        (this->*m_impFn)();
    }
private:
    void implementationA() { /*...*/ }
    void implementationB() { /*...*/ }

    typedef void ( Algorithm::*IMP_FN ) ();
    IMP_FN m_impFn;
};

जाहिर है कि यह केवल व्यावहारिक रूप से उपयोगी है यदि आपको लगता है कि कोड को पर्याप्त रूप से अंकित किया जा रहा है, यदि कथन उदाहरण के लिए चीजों को धीमा कर रहा है। कुछ गहन एल्गोरिदम की हिम्मत में कहीं गहरे। मुझे अभी भी लगता है कि अगर यह उन स्थितियों में भी बयान से ज्यादा सुरुचिपूर्ण है, जहां इसका कोई व्यावहारिक उपयोग नहीं है, लेकिन यह सिर्फ मेरा विकल्प है।


मूल रूप से, आप अमूर्त Algorithmऔर दो व्युत्पन्न वर्गों, जैसे, AlgorithmAऔर AlgorithmB। ऐसे मामले में दोनों एल्गोरिदम को अच्छी तरह से अलग किया जाता है और स्वतंत्र रूप से परीक्षण किया जाना सुनिश्चित किया जाता है।
शिखा

2

कक्षाओं के लिए संकेत असली संकेत नहीं हैं ; एक वर्ग एक तार्किक निर्माण है और स्मृति में कोई भौतिक अस्तित्व नहीं है, हालांकि, जब आप किसी कक्षा के सदस्य को एक सूचक का निर्माण करते हैं तो यह सदस्य के वर्ग के ऑब्जेक्ट में एक ऑफसेट देता है जहां सदस्य पाया जा सकता है; यह एक महत्वपूर्ण निष्कर्ष देता है: चूंकि स्थैतिक सदस्य किसी भी वस्तु से जुड़े नहीं होते हैं, इसलिए एक सदस्य के लिए एक सूचक एक स्थिर सदस्य (डेटा या फ़ंक्शन) को इंगित नहीं कर सकता है जो भी निम्नलिखित पर विचार करें:

class x {
public:
    int val;
    x(int i) { val = i;}

    int get_val() { return val; }
    int d_val(int i) {return i+i; }
};

int main() {
    int (x::* data) = &x::val;               //pointer to data member
    int (x::* func)(int) = &x::d_val;        //pointer to function member

    x ob1(1), ob2(2);

    cout <<ob1.*data;
    cout <<ob2.*data;

    cout <<(ob1.*func)(ob1.*data);
    cout <<(ob2.*func)(ob2.*data);


    return 0;
}

स्रोत: संपूर्ण संदर्भ C ++ - हर्बर्ट शिल्ड्ट 4 संस्करण


0

मुझे लगता है कि आप केवल ऐसा करना चाहते हैं यदि सदस्य डेटा बहुत बड़ा था (उदाहरण के लिए, एक अन्य सुंदर वर्ग की वस्तु), और आपके पास कुछ बाहरी दिनचर्या है जो केवल उस वर्ग की वस्तुओं के संदर्भ में काम करती है। आप सदस्य ऑब्जेक्ट को कॉपी नहीं करना चाहते हैं, तो इससे आप इसे पास कर सकते हैं।


0

यहां एक उदाहरण है जहां डेटा सदस्यों के लिए सूचक उपयोगी हो सकता है:

#include <iostream>
#include <list>
#include <string>

template <typename Container, typename T, typename DataPtr>
typename Container::value_type searchByDataMember (const Container& container, const T& t, DataPtr ptr) {
    for (const typename Container::value_type& x : container) {
        if (x->*ptr == t)
            return x;
    }
    return typename Container::value_type{};
}

struct Object {
    int ID, value;
    std::string name;
    Object (int i, int v, const std::string& n) : ID(i), value(v), name(n) {}
};

std::list<Object*> objects { new Object(5,6,"Sam"), new Object(11,7,"Mark"), new Object(9,12,"Rob"),
    new Object(2,11,"Tom"), new Object(15,16,"John") };

int main() {
    const Object* object = searchByDataMember (objects, 11, &Object::value);
    std::cout << object->name << '\n';  // Tom
}

0

मान लीजिए कि आपके पास एक संरचना है। उस संरचना के अंदर * कुछ प्रकार के नाम * एक ही प्रकार के दो चर लेकिन अलग अर्थ के साथ हैं

struct foo {
    std::string a;
    std::string b;
};

ठीक है, अब कहते हैं कि आपके पास fooएक कंटेनर में एस का एक गुच्छा है :

// key: some sort of name, value: a foo instance
std::map<std::string, foo> container;

ठीक है, अब मान लीजिए कि आप डेटा को अलग-अलग स्रोतों से लोड करते हैं, लेकिन डेटा एक ही फैशन में प्रस्तुत किया जाता है (उदाहरण के लिए, आपको एक ही पार्सिंग विधि की आवश्यकता है)।

आप ऐसा कुछ कर सकते हैं:

void readDataFromText(std::istream & input, std::map<std::string, foo> & container, std::string foo::*storage) {
    std::string line, name, value;

    // while lines are successfully retrieved
    while (std::getline(input, line)) {
        std::stringstream linestr(line);
        if ( line.empty() ) {
            continue;
        }

        // retrieve name and value
        linestr >> name >> value;

        // store value into correct storage, whichever one is correct
        container[name].*storage = value;
    }
}

std::map<std::string, foo> readValues() {
    std::map<std::string, foo> foos;

    std::ifstream a("input-a");
    readDataFromText(a, foos, &foo::a);
    std::ifstream b("input-b");
    readDataFromText(b, foos, &foo::b);
    return foos;
}

इस बिंदु पर, कॉलिंग readValues()"इनपुट-ए" और "इनपुट-बी" के एक साथ एक कंटेनर लौटाएगा; सभी चाबियाँ मौजूद होंगी, और जिनके पास या तो एक या बी या दोनों होंगे।


0

सिर्फ @ एनॉन के @ ओक्लासिस्ट के उत्तर के लिए कुछ उपयोग के मामलों को जोड़ने के लिए, यहां पॉइंटर-टू-मेंबर-फ़ंक्शन और पॉइंटर-टू-मेंबर-डेटा के बारे में एक महान पढ़ने की सामग्री है।

https://www.dre.vanderbilt.edu/~schmidt/PDF/C++-ptmf4.pdf


लिंक मर चुका है। इसीलिए लिंक-ओनली उत्तरों की यहाँ अपेक्षा नहीं है। कम से कम लिंक की सामग्री को संक्षेप में प्रस्तुत करें, अन्यथा लिंक
रो जाने पर
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.