将任何类型的值存储为最初在C ++中的模板化工厂方法中提供的类型?

时间:2009-10-16 09:29:46

标签: c++ design-patterns templates types

这与我最近提出的这个问题([Accessing a method from a templated derived class without using virtual functions in c++?)略有不同。

我想使用模板化工厂方法创建对象的实例,然后从那时起只能根据提供给项目的初始类型设置和获取值。

以下是我正在努力实现的一个简单示例:

boost::shared_ptr<Item> item = Item::create<float>();

item->setValue(5);                  // conversion to 5.0 in setting the value
float value = item->value();        // returned value = 5.0

基本上,setValue失败的唯一时间是,如果没有从Item中提供给内部值的初始'type'的任何隐式转换。

因此,如果我将整个Item类作为一个带有类型的模板化类,我需要在每次创建一个指向Item的共享指针时提供值的类型,我并不关心。

我采用的下一个方法是尝试将初始类型存储在类中,并使用boost :: any作为内部存储,如果存在隐式转换,则将内部类型转换为指定的初始类型。但是,我试图存储并比较类型信息,最初查看std :: type_info,但是当setValue采用boost :: any时,没有办法比较实际传递的内容。

(对此的轻微扩展可能是在创建中为模板参数提供变体样式的选项列表,并在本机提供的类型中返回值。)

可能有一种我不知道的设计模式,或者我没有考虑过的不同方法,所以我有兴趣听听有关如何解决此问题的任何建议?

4 个答案:

答案 0 :(得分:2)

考虑一下:

boost::shared_ptr<Item> item1 = Item::create<float>();
boost::shared_ptr<Item> item2 = Item::create<string>();

item1和item2具有相同的(静态)类型:boost :: shared_ptr。因此,没有任何方法可以进行编译:

item2.setValue("foo");

并且无法编译:

item1.setValue("foo");

我不确定你在说什么“如果我把整个Item类作为一个模板类的一个模板类,我需要在每次调用setValue或value时定义它(setValue&lt; float&gt;(5) )”。听起来你实际上是在谈论使每个方法模板化,而不是全班。如果Item类是模板化的,那么你可以写:

boost::shared_ptr<Item<float> > item = Item<float>::create();

然后您可以轻松地让setValue()方法只接受匹配类型。

答案 1 :(得分:2)

这对你有用吗?

#include <iostream>
#include <boost/shared_ptr.hpp>

using namespace std;
using namespace boost;

template<typename T> class Item
{
    Item(); // prohibited
    Item (const T & t) : m_value(t) {}
public :
    static shared_ptr<Item<T>> Create(const T & t) 
    { return shared_ptr<Item<T>>(new Item<T>(t)); }
    const T & getValue() const { return m_value; }
    void setValue(const T & v) { m_value = v; }
private :
    T m_value;
};

template<typename T> class Factory
{
public :
    static shared_ptr<Item<T>> CreateItem(const T & value)
    { return Item<T>::Create(value); }
};

void main()
{
    shared_ptr<Item<int>> a = Factory<int>::CreateItem(5);
    shared_ptr<Item<float>> b = Factory<float>::CreateItem(6.2f);
    std::cout << a->getValue() << std::endl;
    std::cout << b->getValue() << std::endl;
    a->setValue(3);
    b->setValue(10.7f);
    std::cout << a->getValue() << std::endl;
    std::cout << b->getValue() << std::endl;
}
  • 编辑 - 强制执行更加持久的纳粹主义。

答案 2 :(得分:1)

这听起来与boost.any非常相似。你看过这个了吗?

答案 3 :(得分:1)

你对boost :: any的问题是它太灵活了。它背后的基本理念仍然是理智的。您需要做的是将初始值包装在template<typename T> class ItemOfType<T> : public Item类型的对象中。然后Item::create<T>将返回这样一个类型化的对象。如果您稍后尝试分配U,则首先测试dynamic_cast this ItemOfType<U>* T==U。这涵盖了您的U案例。

更难的部分是T是否可分配给create<T>的问题。通常的解决方案是实例化模板,但在U中,您没有Item::operator=(U const),而在T中,您没有原始{{1}}。