2014-11-28 3 views
6

У меня есть шаблон класса, который должен иметь возможность сравнить между двумя объектами, с помощью объектов сравнения, полученных из Compare класса у меня есть:Условно применять типы шаблонов в C++

template<typename T> 
class Container { 
public: 
    template<typename A, typename B> 
    class Compare { 
    public: 
     virtual bool eq(const A&, const B&) const = 0; 
    }; 

Я обеспечиваю сравнение по умолчанию объектов а, при условии, тип T имеет оператор ==:

template<typename A, typename B> 
    class Default : public Compare<A,B> { 
    public: 
     bool eq(const A& a, const B& b) const { return a==b; } 
    }; 
private: 
    Compare<T,T>* comparison_object; 
    bool uses_default; 
    Container() : comparison_object(new Default<T,T>()), uses_default(true) {} 
    Container(Compare<T,T>& cmp) : comparison_object(&cmp), uses_default(false) {} 
    ~Container() { if(uses_default) delete comparison_object; } 
}; 

Однако, когда я пытаюсь скомпилировать это с помощью пользовательского класса, который не имеютперегрузки (даже если указать объект, полученный из Compare):

MyObjCmp moc; 
Container<MyObj>(&moc); 

Компилятор жалуется, что оператор не существует:

error: no match for 'operator==' (operand types are 'const MyObj' and 'const MyObj') 

Это имеет смысл, потому что Default класс по-прежнему должен быть создан, хотя я не нуждаюсь в этом. Но теперь мне нужно обходное решение ...

Любые идеи?

+0

'Сравнить * compare_object;' Это вызывает утечку памяти. используйте 'std :: unique_ptr' или' std :: shared_ptr', вместо того, чтобы напрямую использовать 'new' /' delete' – ikh

+1

Мой деструктор позаботится об этом ... У меня есть флаг boolean default_created и условное удаление, don 't worry :) – Dori

+0

@Niall, я отредактирую его ... Я думал, что это неважно – Dori

ответ

4

Вместо того, проверка времени выполнения для нулевого указателя, вы можете использовать проверку во время компиляции для не объекта:

Container() : comparison_object(new Default<T,T>), uses_default(true) {} 
Container(Compare<T,T>& cmp) : comparison_object(&cmp), uses_default(false) {} 

конструктора по умолчанию, и, следовательно, Default, будет инстанцировано только в случае необходимости, поэтому нет ошибки при использовании конструктора, отличного от стандартного, с типом, для которого Default потерпит неудачу.

Но будьте осторожны с жонглированием необработанными указателями, это рецепт утечек памяти и еще хуже. Не забывайте, что виртуальный деструктор для Compare и Rule of Three, и будьте очень осторожны, что компаратор не по умолчанию не будет неожиданно уничтожен. Еще лучше используйте интеллектуальный указатель, чтобы заботиться обо всем этом.

+0

Но мне все еще нужно проверить NULL во втором конструкторе, и при необходимости создать 'Default ' ...назад к квадрату – Dori

+0

@Dori: Действительно, я забыл упомянуть, что вы должны взять ссылку, а не указатель, чтобы убедиться, что она не может быть нулевой. Если вы хотите использовать компаратор по умолчанию, используйте конструктор по умолчанию. –

+0

Нет. Хотя компилятор читает эту строку, он будет создавать экземпляр 'Default ', не так ли? – ikh

0
template<typename T1, typename T2 > 
class Container { 
public: 
    template<typename T3, typename T4 > 
    class Compare { 
    public: 
     virtual bool eq(const T1&, const T2&) const = 0; 
    }; 


    class Default : public Compare { 
    public: 
     bool eq(const T1& a, const T2& b) const { return a==b; } 
    }; 

private: 
    Compare<T1,T2>* comparison_object; 
    bool uses_default; 
    Container(Compare<T1,T2>* cmp) : comparison_object(cmp), uses_default(false) { 
     if (!cmp) { 
      comparison_object = new Default<T,T>(); 
      uses_default = true; 
     } 
    } 
    ~Container() { if(uses_default) delete comparison_object; } 
}; 
Смежные вопросы