Pointer-to-global-instance-of-template-class sebagai parameter-template?

Saya mencoba menerapkan versi umum dari kode di bawah ini:

#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;
}

Apa yang ingin saya miliki (jika memungkinkan) adalah satu kelas templat Pekerja, yang dapat dipakai untuk bekerja di salah satu wadah, seperti:

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

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

    private:
        ?? mPtrToContainer_;
};

Namun, setelah beberapa jam, saya masih tidak tahu apa yang seharusnya menjadi '??'. Mungkin penyihir template punya ide?

Pembaruan 1: Memperbaiki kesalahan pada 'operator()' Pekerja (ptrToContainer -> mPtrToContainer_). Maaf untuk itu.

Pembaruan 2: Ada yang berfungsi, namun saya masih penasaran apakah ada yang punya ide lebih baik. Misalnya, memiliki satu parameter template akan menyenangkan. Adakah yang tahu jika "parameter templat templat" dapat membantu dalam situasi ini?

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

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

    private:
        TContainer* mPtrToContainer_;
};

Terimakasih


person Dragos    schedule 15.04.2012    source sumber
comment
Oh, saya melihat jawaban saya yang telah diedit mubazir karena hasil edit Anda :-) Hmm. parameter templat-templat digunakan ketika Anda memiliki tipe yang menggunakan parameter templat, dan Anda menggunakan tipe itu sebagai templat. Saya pikir itu tidak berlaku di sini. Saya mencoba menulis fungsi pembantu penyimpulan tipe, tetapi tidak berhasil juga karena nilai penunjuk adalah bagian dari tanda tangan tipe pekerja. +1, ini lebih menarik dari yang saya kira.   -  person Cameron    schedule 15.04.2012
comment
@Cameron Kompiler produksi saya adalah Intel, yang memiliki beberapa fitur C++11: software.intel.com/en-us/articles/. Fitur baru apa yang diperlukan untuk menggabungkan parameter template?   -  person Dragos    schedule 15.04.2012


Jawaban (1)


Saya akan mencobanya. Bagaimana kalau mengubah template Anda sehingga diberi tipe sebagai parameter, bukan pointer itu sendiri? Anda masih bisa meneruskan pointer ke konstruktor:

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

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

    private:
        TContainer* mPtrToContainer_;
};

Maka Anda bisa menggunakannya seperti:

WorkerOnAnyContainer<ContainerA> workerOnAInstance(&staticInstanceA);

Karena Anda ingin mempertahankan desain pointer-as-template-parameter, Anda dapat menggunakan sesuatu seperti ini:

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

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

    private:
        TContainer* mPtrToContainer_;
};

Dan gunakan seperti:

WorkerOnAnyContainer<ContainerA, &staticInstanceA> workerOnAInstance;

Namun, ini agak berantakan karena Anda memerlukan dua argumen template, dan argumen pertama terasa mubazir. Saya tidak yakin apakah mungkin untuk menyelesaikan ini dengan C++03, tapi saya pikir mungkin untuk membangun metode pembantu yang dapat melakukan pengurangan tipe untuk kita di C++11:

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

Namun, karena kompiler mengharapkan fungsi tersebut berfungsi untuk parameter non-kompilasi-waktu-konstan, ini tidak dapat dikompilasi (GCC 4.6.3):

use of parameter 'container' outside function body

Ternyata Anda bukan satu-satunya yang mencoba melakukan ini. Tampaknya, Anda tidak dapat membuat metode pembantu dengan cara ini, bahkan dengan C++11.

Satu-satunya hal yang menurut saya benar-benar berfungsi adalah menggunakan makro (saya tahu, saya tahu):

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

Kemudian menggunakannya semudah:

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

Ini menggunakan auto dan decltype sederhana, keduanya fitur C++11 yang didukung kompiler Intel C++ pada v12 (walaupun saya belum menguji kode ini dengan apa pun kecuali GCC). Sebagai makro, tentu saja agak rapuh.

Lihat aksinya!

person Cameron    schedule 15.04.2012
comment
Terima kasih atas balasannya. Memang ini yang saya gunakan sampai sekarang. Namun, ini adalah bagian dari model numerik yang lebih besar, dan untuk alasan kinerja saya sekarang ingin memastikan bahwa penunjuk ke wadah tertanam di dalam Pekerja pada waktu kompilasi, untuk membantu kompiler memasukkan beberapa metode (dihilangkan dalam contoh saya) dari kelas Kontainer, yang dipanggil dari Pekerja. Ada ide lagi? - person Dragos; 15.04.2012
comment
Terima kasih banyak atas jawabannya! Tampaknya kami menemukan solusi yang sama, tetapi tidak melakukan sinkronisasi. Tahukah Anda apakah kedua parameter templat dapat digabungkan? Ini adalah masalah sampingan, tentu saja, tapi menurut saya ini mungkin membuat hidup pengguna saya lebih mudah :). - person Dragos; 15.04.2012
comment
@Dragos: Oke, ini jauh lebih rumit dari yang saya kira :-( Satu-satunya solusi (kompilasi) yang dapat saya pikirkan sejauh ini menggunakan makro (sigh). Lihat hasil edit saya. - person Cameron; 15.04.2012