為什麼再談一次,因為上次代碼實在是不夠好。上篇文章 對象工廠給出的代碼太過拙劣,限於學識,我自己類型擦除技術僅僅是把對象的指針轉換為void* 而已,實際上可以更為巧妙。這次利用新的類型擦出技術,給出一個完美的解決方,請看下文。
我
為什麼不直接保存用戶提供的function的void*而非要把他copy一份利用容器vector儲存起來,然後再去取其指針轉換為void*。是因
為用戶傳來的function可能是右值或臨時值,一個馬上要被刪除的值,如果我們直接使用用戶提供的function的void*,該指針很可能是懸垂
指針。
就算以上兩個問題都不是是問題,這樣的代碼實現方式真是拙劣。我自己都無法直視。
所以,我們需要一個能儲存任何元素的容器,該容器類型唯一,這樣我們解決了以上兩個麻煩。
其一,我們不在需要創建多個容器,因為這個類型的容器可以儲存任何類型的元素。
其二,我們的注銷方法不在需要強迫用戶給出具體的類型信息,因為容器知道如何刪除元素,原因在於容器類型保留下來。
一個能儲存任何元素類型的容器,在Java中也許是這樣ArrayList<Object>,因為所有類均繼承子Object。恩,在C++中如何實現,C++中缺少這樣一個父類!
早聞boost大名,但一直以為stl都沒有完全搞懂,所以不想去研究boost,但boost真的能為我們提供一個可以儲存任何類型的容器。他就是boost::any,我這裡深入介紹boost::any,把源碼貼出來分享給大家。
class any
{
public: // structors
any() BOOST_NOEXCEPT
: content(0)
{
}
template<typename ValueType>
any(const ValueType & value)
: content(new holder<
BOOST_DEDUCED_TYPENAME remove_cv<BOOST_DEDUCED_TYPENAME decay<const ValueType>::type>::type
>(value))
{
}
any(const any & other)
: content(other.content ? other.content->clone() : 0)
{
}
#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
// Move constructor
any(any&& other) BOOST_NOEXCEPT
: content(other.content)
{
other.content = 0;
}
// Perfect forwarding of ValueType
template<typename ValueType>
any(ValueType&& value
, typename boost::disable_if<boost::is_same<any&, ValueType> >::type* = 0 // disable if value has type `any&`
, typename boost::disable_if<boost::is_const<ValueType> >::type* = 0) // disable if value has type `const ValueType&&`
: content(new holder< typename decay<ValueType>::type >(static_cast<ValueType&&>(value)))
{
}
#endif
~any() BOOST_NOEXCEPT
{
delete content;
}
public: // modifiers
any & swap(any & rhs) BOOST_NOEXCEPT
{
std::swap(content, rhs.content);
return *this;
}
#ifdef BOOST_NO_CXX11_RVALUE_REFERENCES
template<typename ValueType>
any & operator=(const ValueType & rhs)
{
any(rhs).swap(*this);
return *this;
}
any & operator=(any rhs)
{
any(rhs).swap(*this);
return *this;
}
#else
any & operator=(const any& rhs)
{
any(rhs).swap(*this);
return *this;
}
// move assignement
any & operator=(any&& rhs) BOOST_NOEXCEPT
{
rhs.swap(*this);
any().swap(rhs);
return *this;
}
// Perfect forwarding of ValueType
template <class ValueType>
any & operator=(ValueType&& rhs)
{
any(static_cast<ValueType&&>(rhs)).swap(*this);
return *this;
}
#endif
public: // queries
bool empty() const BOOST_NOEXCEPT
{
return !content;
}
void clear() BOOST_NOEXCEPT
{
any().swap(*this);
}
const boost::typeindex::type_info& type() const BOOST_NOEXCEPT
{
return content ? content->type() : boost::typeindex::type_id<void>().type_info();
}
#ifndef BOOST_NO_MEMBER_TEMPLATE_FRIENDS
private: // types
#else
public: // types (public so any_cast can be non-friend)
#endif
class placeholder
{
public: // structors
virtual ~placeholder()
{
}
public: // queries
virtual const boost::typeindex::type_info& type() const BOOST_NOEXCEPT = 0;
virtual placeholder * clone() const = 0;
};
template<typename ValueType>
class holder : public placeholder
{
public: // structors
holder(const ValueType & value)
: held(value)
{
}
#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
holder(ValueType&& value)
: held(static_cast< ValueType&& >(value))
{
}
#endif
public: // queries
virtual const boost::typeindex::type_info& type() const BOOST_NOEXCEPT
{
return boost::typeindex::type_id<ValueType>().type_info();
}
virtual placeholder * clone() const
{
return new holder(held);
}
public: // representation
ValueType held;
private: // intentionally left unimplemented
holder & operator=(const holder &);
};
#ifndef BOOST_NO_MEMBER_TEMPLATE_FRIENDS
private: // representation
template<typename ValueType>
friend ValueType * any_cast(any *) BOOST_NOEXCEPT;
template<typename ValueType>
friend ValueType * unsafe_any_cast(any *) BOOST_NOEXCEPT;
#else
public: // representation (public so any_cast can be non-friend)
#endif
placeholder * content;
};
在上述代碼中,關鍵是要理解placeholder和holder,實際上 placeholder充當了Java中Object,作為萬物的父類。holder是我們的類的一個包裝,聚合我們的類對象。而any類持有一個執行包 裝類的父類指針。另外,在any類的實現這裡用到了虛復制構造函數技術。
來吧,先把代碼貼上來,talking is cheap,show you the code.
template <typename AbstractProduct ,typename IdentifierType = string> class Factory
{
public:
template <typename... Arg> bool Register(const IdentifierType& id,const function<unique_ptr<AbstractProduct>(Arg...)>& creator)
{
typename AssocMap::const_iterator i =associations_.find(id);
if(i!= associations_.end()) return false;
return associations_.insert(typename AssocMap::value_type(id,creator)).second;
}
bool UnRegister(const IdentifierType& id)
{
typename AssocMap::const_iterator i =associations_.find(id);
return associations_.erase(id)==1;
}
template <typename... Arg> unique_ptr<AbstractProduct> Createobject(const IdentifierType& id,Arg&&... args)
{
typename AssocMap::const_iterator i =associations_.find(id);
if(i != associations_.end())
{
auto funp=boost::any_cast<std::function<unique_ptr<AbstractProduct>(Arg...)> >(&(i->second));//i->second類型是boost::any
assert(funp);//如果無法轉換,funp將是空指針
return (*funp)(std::forward<Arg>(args)...);//完美轉發
}
assert(false);
}
private:
typedef std::unordered_map<IdentifierType,boost::any> AssocMap;//存儲任意類型的map
AssocMap associations_;
};
代碼瞬間簡單了很多,我再關鍵位置加入了注釋,上述代碼使用 變長參數模板技術,完美轉發,智能指針,unordered_map,所以要想通過編譯,必須啟用C++11。據我所知,不成形的C++17標准已經出來了,所以盡快熟悉新標准吧。當然還需要boost庫支持。
你需要靈活性,則需要花費性能,靈活性不是沒有代價的,我們的靈活性在於我的工廠支持注冊任意形式調用形式,只要求函數的返回值,但我們使用RTTI和模板技術必然影響性能。具體要不要用,取決於實際需要。