Это интересная проблема, но давайте сначала обсудим ошибку компилятора.
Как сказал компилятор, функция не может быть одновременно виртуальной и шаблонной. Чтобы понять почему, просто подумайте о реализации: в большинстве случаев объекты с виртуальными функциями имеют виртуальную таблицу, в которой хранится указатель на каждую функцию.
Однако для шаблонов существует столько же функций, сколько и комбинаций типов: как должна выглядеть виртуальная таблица? Невозможно сказать во время компиляции, и структура памяти вашего класса включает в себя виртуальную таблицу, и имеет , который будет определен во время компиляции.
Теперь к вашей проблеме.
Самое простое решение - написать один виртуальный метод для каждого типа, конечно, это может скоро стать утомительным, поэтому давайте представим, что вы этого не слышали.
Если Mesh
не должен знать о различных типах, то, конечно, вам не нужно, чтобы эта функция была virtual
, потому что кто бы знал, учитывая экземпляр Mesh
, с каким типом вызывается функция?
Mesh* mesh = ...;
mesh.createChannel<int>(); // has it been defined for that `Mesh` ??
С другой стороны, я предполагаю, что OpenGLMesh
точно знает, какой тип TypedChannel
ему понадобится. Если это так, мы могли бы использовать очень простой трюк.
struct ChannelFactory
{
virtual ~ChannelFactory() {}
virtual Channel* createChannel() = 0;
};
template <class T>
struct TypedChannelFactory: ChannelFactory
{
};
А потом:
class Mesh
{
public:
template <class T>
Channel* addChannel()
{
factories_type::const_iterator it = mFactories.find(typeid(T).name());
assert(it != mFactories.end() && "Ooops!!!" && typeid(T).name());
Channel* channel = it->second->createChannel();
mChannels.push_back(channel);
return channel;
} // addChannel
protected:
template <class T>
void registerChannelFactory(TypedChannelFactory<T>* factory)
{
mFactories.insert(std::make_pair(typeid(T).name(), factory));
} // registerChannelFactory
private:
typedef std::map < const char*, ChannelFactory* const > factories_type;
factories_type mFactories;
std::vector<Channel*> mChannels;
}; // class Mesh
Это демонстрирует довольно мощную идиому, известную как type erasure
. Вы, вероятно, использовали его еще до того, как узнали его имя:)
Теперь вы можете определить OpenGLMesh
как:
template <class T>
struct OpenGLChannelFactory: TypedChannelFactory<T>
{
virtual Channel* createChannel() { return new OpenGLChannel<T>(); }
};
OpenGLMesh::OpenGLMesh()
{
this->registerChannelFactory(new OpenGLChannelFactory<int>());
this->registerChannelFactory(new OpenGLChannelFactory<float>());
}
И вы будете использовать его как:
OpenGLMesh openGLMesh;
Mesh& mesh = openGLMesh;
mesh.addChannel<int>(); // fine
mesh.addChannel<float>(); // fine
mesh.addChannel<char>(); // ERROR: fire the assert... (or throw, or do nothing...)
Надеюсь, я понял, что вам нужно: p