2012-04-15 2 views
1

Я пытаюсь реализовать общую версию кода ниже:Указатель-в-global-instance-of-template-class как шаблон-параметр?

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

То, что я хотел бы иметь (если это вообще возможно) является один рабочий шаблон класса, который может быть создан для работы на любом контейнере, что-то вроде:

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

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

    private: 
     ?? mPtrToContainer_; 
}; 

Однако, через несколько часов, я до сих пор не могу понять, что «??» s должно быть. Может быть, у мастера шаблонов есть идея?

Обновление 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

+1

О, я вижу, мой отредактированный ответ избыточен дали ваши изменения :-) Хм. Параметры шаблона шаблона относятся к типу, который принимает параметр шаблона, и вы используете этот тип в качестве шаблона. Я не думаю, что это применимо здесь. Я попробовал написать вспомогательную функцию типа-inferring, но это не работает либо потому, что значение указателя является частью сигнатуры рабочего типа. +1, это более интересно, чем я думал. – Cameron

+0

Вы используете C++ 11? – Cameron

+0

@Cameron Мой «производственный» компилятор - это Intel, у которого есть некоторые возможности C++ 11: http://software.intel.com/en-us/articles/c0x-features-supported-by-intel-c-compiler/ , Какие новые функции потребуются для объединения параметров шаблона? – Dragos

ответ

3

Я дам ему шанс. Как насчет смены шаблона так, чтобы ему присваивался тип как параметр, а не сам указатель? Вы все еще можете передать указатель на конструктор:

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>(); 
} 

Но , так как компилятор ожидает, что функция работать не-компиляция время сопзИте параметры, это не компилируется (GCC 4.6.3):

use of parameter 'container' outside function body 

оказывается you're not the only one trying to do this. По-видимому, вы не можете создать вспомогательный метод таким образом, даже с C++ 11.

Единственное, что я могу думать о том, что на самом деле работает, чтобы использовать макрос (я знаю, я знаю):

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

Затем, используя это так же просто, как:

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

Этом использует auto и простой decltype, оба C++ 11, которые поддерживает компилятор Intel C++ с версии 12 (хотя я не тестировал этот код ни с чем, кроме GCC). Будучи макросом, он, конечно, немного хрупкий.

See it in action!

+0

Благодарим вас за ответ. Действительно, это то, что я использовал до сих пор. Однако это часть более крупной численной модели, и по соображениям производительности я теперь хочу, чтобы указатель на контейнер был встроен внутри Рабочего во время компиляции, чтобы помочь компилятору встроить некоторые методы (опущенные в моем примере) из Контейнер-класс, который вызывается от Рабочих. Есть еще идеи? – Dragos

+0

@Dragos: Смотрите мое редактирование. Надеюсь, поможет! – Cameron

+0

Спасибо за ответ! Кажется, мы придумали одно и то же решение, но не синхронизировали. Вы знаете, можно ли комбинировать два параметра шаблона? Это, конечно, проблема, но я думаю, что это может облегчить жизнь моих пользователей :). – Dragos

Смежные вопросы