ตัวชี้สู่ระดับโลกอินสแตนซ์ของคลาสเทมเพลตเป็นพารามิเตอร์เทมเพลต?

ฉันกำลังพยายามใช้โค้ดเวอร์ชันทั่วไปด้านล่าง:

#include <iostream>

class ContainerA
{
    public:
        ContainerA( int newData )
            : mData_(newData)
        {}
        int mData_;
};

class ContainerB
{
    public:
        ContainerB( int newData )
            : mData_(newData)
        {}
        int mData_;
};

ContainerA staticInstanceA( 3 );
ContainerB staticInstanceB( 11 );

template< ContainerA* ptrToContainer >
class WorkerOnA
{
    public:
        WorkerOnA( )
            : mPtrToContainer_(ptrToContainer)
        {}

        void operator()()
        {
            std::cout << "Data = " << mPtrToContainer_->mData_ << '\n';
        }

    private:
        ContainerA* mPtrToContainer_;
};

template< ContainerB* ptrToContainer >
class WorkerOnB
{
    public:
        WorkerOnB( )
            : mPtrToContainer_(ptrToContainer)
        {}

        void operator()()
        {
            std::cout << "Data = " << mPtrToContainer_->mData_ << '\n';
        }

    private:
        ContainerB* mPtrToContainer_;
};

int main( )
{
    WorkerOnA<&staticInstanceA> workerOnAInstance;
    WorkerOnB<&staticInstanceB> workerOnBInstance;

    workerOnAInstance();
    workerOnBInstance();

    return 0;
}

สิ่งที่ฉันต้องการ (ถ้าเป็นไปได้เลย) คือคลาสเทมเพลต Worker เดียว ซึ่งสามารถอินสแตนซ์ให้ทำงานบนคอนเทนเนอร์ใดก็ได้ เช่น:

template< ?? ptrToContainer >
class WorkerOnAnyContainer
{
    public:
        WorkerOnA( )
            : mPtrToContainer_(ptrToContainer)
        {}

        void operator()()
        {
            std::cout << "Data = " << mPtrToContainer_->mData_ << '\n';
        }

    private:
        ?? mPtrToContainer_;
};

อย่างไรก็ตาม หลังจากผ่านไปหลายชั่วโมง ฉันก็ยังนึกไม่ออกว่าตัวอักษร '??' ควรเป็นอย่างไร บางทีตัวช่วยสร้างเทมเพลตอาจมีแนวคิดใช่ไหม

อัปเดต 1: แก้ไขข้อผิดพลาดใน 'ตัวดำเนินการ ()' ของผู้ปฏิบัติงาน (ptrToContainer -> mPtrToContainer_) ขอโทษสำหรับสิ่งนั้น.

อัปเดต 2: ฉันได้สิ่งที่ได้ผลแล้ว แต่ฉันก็ยังอยากรู้ว่าใครมีความคิดที่ดีกว่านี้ไหม ตัวอย่างเช่น การมีพารามิเตอร์เทมเพลตเพียงตัวเดียวก็น่าจะดี ไม่มีใครรู้ว่า "พารามิเตอร์เทมเพลตเทมเพลต" สามารถช่วยในสถานการณ์นี้ได้หรือไม่

template< class TContainer, TContainer* ptrToContainer >
class Worker
{
    public:
        Worker( )
            : mPtrToContainer_(ptrToContainer)
        {}

        void operator()()
        {
            std::cout << "Data = " << mPtrToContainer_->mData_ << '\n';
        }

    private:
        TContainer* mPtrToContainer_;
};

ขอบคุณ D


person Dragos    schedule 15.04.2012    source แหล่งที่มา
comment
โอ้ ฉันเห็นว่าคำตอบที่แก้ไขแล้วของฉันซ้ำซ้อนกับการแก้ไขของคุณ :-) อืม พารามิเตอร์ template-template มีไว้สำหรับเมื่อคุณมีประเภทที่ใช้พารามิเตอร์เทมเพลต และคุณใช้ประเภทนั้นเป็นเทมเพลต ฉันไม่คิดว่ามันจะใช้ที่นี่ ฉันพยายามเขียนฟังก์ชันตัวช่วยอนุมานประเภท แต่ก็ไม่ได้ผลเช่นกันเนื่องจากค่าตัวชี้เป็นส่วนหนึ่งของลายเซ็นประเภทผู้ปฏิบัติงาน +1 นี่น่าสนใจมากกว่าที่ฉันคิดไว้   -  person Cameron    schedule 15.04.2012
comment
@Cameron คอมไพเลอร์การผลิตของฉันเป็นของ Intel ซึ่งมีคุณสมบัติ C ++ 11 บางอย่าง: software.intel.com/en-us/articles/ คุณลักษณะใหม่ใดบ้างที่จำเป็นสำหรับการรวมพารามิเตอร์เทมเพลต   -  person Dragos    schedule 15.04.2012


คำตอบ (1)


ฉันจะให้มันยิง ลองเปลี่ยนเทมเพลตของคุณเพื่อให้ประเภทเป็นพารามิเตอร์แทนที่จะเป็นตัวชี้เองล่ะ คุณยังคงสามารถส่งพอยน์เตอร์ไปยังตัวสร้างได้:

template< typename TContainer >
class WorkerOnAnyContainer
{
    public:
        WorkerOnA( TContainer* ptrToContainer )
            : mPtrToContainer_(ptrToContainer)
        {}

        void operator()()
        {
            std::cout << "Data = " << mPtrToContainer_->mData_ << '\n';
        }

    private:
        TContainer* mPtrToContainer_;
};

จากนั้นคุณสามารถใช้มันเช่น:

WorkerOnAnyContainer<ContainerA> workerOnAInstance(&staticInstanceA);

เนื่องจากคุณต้องการคงการออกแบบพารามิเตอร์ตัวชี้ตามเทมเพลต คุณสามารถดำเนินการดังนี้:

template< typename TContainer, TContainer* ptrToContainer >
class WorkerOnAnyContainer
{
    public:
        WorkerOnA()
            : mPtrToContainer_(ptrToContainer)
        {}

        void operator()()
        {
            std::cout << "Data = " << ptrToContainer->mData_ << '\n';
        }

    private:
        TContainer* mPtrToContainer_;
};

และใช้มันเหมือน:

WorkerOnAnyContainer<ContainerA, &staticInstanceA> workerOnAInstance;

แต่นี่ค่อนข้างยุ่งเนื่องจากคุณต้องการอาร์กิวเมนต์เทมเพลตสองรายการ และอาร์กิวเมนต์แรกรู้สึกว่าซ้ำซ้อน ฉันไม่แน่ใจว่าเป็นไปได้ที่จะแก้ปัญหานี้ด้วย C ++ 03 แต่ฉันคิดว่ามันจะเป็นไปได้ที่จะสร้างวิธีการช่วยเหลือที่สามารถทำการหักประเภทให้เราใน C ++ 11:

template<typename T>
auto CreateWorker(T* container) -> WorkerOnAnyContainer<T, container>
{
    return WorkerOnAnyContainer<T, container>();
}

แต่เนื่องจากคอมไพเลอร์คาดว่าฟังก์ชันจะทำงานสำหรับพารามิเตอร์ที่ไม่คอมไพล์-เวลา-const สิ่งนี้จึงไม่คอมไพล์ (GCC 4.6.3):

use of parameter 'container' outside function body

ปรากฎว่า คุณไม่ใช่คนเดียวที่พยายามทำสิ่งนี้. เห็นได้ชัดว่าคุณไม่สามารถสร้างวิธีการช่วยเหลือด้วยวิธีนี้ได้แม้จะใช้ C ++ 11 ก็ตาม

สิ่งเดียวที่ฉันคิดว่าใช้งานได้จริงคือการใช้มาโคร (ฉันรู้ ฉันรู้):

#define CreateWorker(container) WorkerOnAnyContainer<decltype(container), &container>()

จากนั้นใช้งานก็ง่ายเพียง:

auto worker = CreateWorker(staticInstanceA);    // Note no `&'

สิ่งนี้ใช้ประโยชน์จาก auto และ decltype แบบง่าย ทั้งคุณสมบัติ C ++ 11 ที่คอมไพเลอร์ Intel C ++ รองรับตั้งแต่ v12 (แม้ว่าฉันจะไม่ได้ทดสอบโค้ดนี้กับสิ่งใดเลยยกเว้น GCC) ด้วยความที่เป็นมาโคร แน่นอนว่ามันเปราะบางนิดหน่อย

ดูการทำงานจริง!

person Cameron    schedule 15.04.2012
comment
ขอบคุณสำหรับการตอบกลับ. อันที่จริงนี่คือสิ่งที่ฉันใช้มาจนถึงตอนนี้ อย่างไรก็ตาม นี่เป็นส่วนหนึ่งของโมเดลตัวเลขที่ใหญ่กว่า และด้วยเหตุผลด้านประสิทธิภาพ ตอนนี้ฉันต้องการให้แน่ใจว่าตัวชี้ไปยังคอนเทนเนอร์ถูกฝังอยู่ภายใน Worker ในเวลาคอมไพล์ เพื่อช่วยคอมไพเลอร์อินไลน์วิธีการบางอย่าง (ละเว้นในตัวอย่างของฉัน) จาก คอนเทนเนอร์คลาสซึ่งถูกเรียกจากคนงาน มีความคิดเพิ่มเติมบ้างไหม? - person Dragos; 15.04.2012
comment
ขอบคุณมากสำหรับคำตอบ! ดูเหมือนว่าเราจะคิดวิธีแก้ปัญหาแบบเดียวกัน แต่ไม่ได้ซิงโครไนซ์ คุณรู้หรือไม่ว่าสามารถรวมพารามิเตอร์เทมเพลตทั้งสองเข้าด้วยกันได้หรือไม่ แน่นอนว่านี่เป็นปัญหาข้างเคียง แต่ฉันคิดว่ามันอาจทำให้ชีวิตผู้ใช้ของฉันง่ายขึ้น :) - person Dragos; 15.04.2012
comment
@Dragos: ตกลง มันซับซ้อนกว่าที่ฉันคิดไว้มาก :-( วิธีแก้ปัญหา (รวบรวม) เดียวที่ฉันคิดได้จนถึงตอนนี้คือใช้มาโคร (ถอนหายใจ) ดูการแก้ไขของฉัน - person Cameron; 15.04.2012