Practical Type Erasure - Cheinan Marks - CppCon2014
Practical Type Erasure - Cheinan Marks - CppCon2014
Code: https://github.com/cheinan/any_config
Tag: cppcon2014
Cheinan Marks
Outline
!
What is type erasure?
!
How does it work?
!
boost::any
!
Practical type erasure
!
Conclusion
Type Erasure
class C
{
public:
template<typename TInject> C(TInject injectedInstance);
void invoke();
};
Type Erasure: Implementation
class C
{
public:
template<typename TInject> C(TInject injectedInstance)
: m_internalBase(new CInjected<TInject>(injectedInstance)) {}
void invoke() { m_internalBase->DoIt(); }
private:
struct CInternalBase
{
Type Erasure
virtual void DoIt() {}
virtual ~CInternalBase() {}
};
std::shared_ptr<CInternalBase> m_internalBasePtr;
};
Boost Any
#include <vector>
#include <string>
#include <iostream>
#include <boost/any.hpp>
int main()
{
boost::any a = std::string("Anything?");
std::vector<std::string> v = {"Anything!"};
a = v;
a = 5;
return 0;
}
http://www.artima.com/cppsource/type_erasure.html
Type Erasure [is] the Glue between OO and Generic Programming
– Thomas Becker
Client Facing Front End
class CAnyProperty
{
public:
typedef std::shared_ptr<CAnyHandlerBase> THandlerPtr;
template<typename T> void Set( const std::string & key, const T & value )
virtual void Set( const std::string & key, const boost::any & /*value*/ )
{
throw CAnyPropertyException(CAnyPropertyException::eNoSet);
}
class CAnyProperty
{
public:
template<typename T> T Get( const std::string & key ) const
{
return boost::any_cast<T>( x_GetAny( key, typeid( T ) ) );
}
template<typename T> void Set( const std::string & key, const T & value )
{
x_SetAny( key, value );
}
};
Glue Getter
boost::any
CAnyProperty::x_GetAny( const std::string & key,
const Loki::TypeInfo & value_type ) const
{
if ( key.empty() ) throw CAnyPropertyException(CAnyPropertyException::eEmptyKey);
CQueryHandler a_query_handler =
for_each_if( handler_list.begin(), handler_list.end(), CQueryHandler( key ) );
if ( a_query_handler.GetValue().empty() ) {
throw CAnyPropertyNoKeyException( eKeyNotFound, key );
}
boost::any a = a_query_handler.GetValue();
return a;
}
Glue Getter
/// Execute the handler function and look for a return value.
bool operator() ( CAnyProperty::THandlerPtr handler_ptr )
{
assert(m_Value.empty());
m_Value = handler_ptr->Get( m_Key );
return ! m_Value.empty();
}
private:
std::string m_Key;
boost::any m_Value;
};
Glue Setter
void CAnyProperty::x_SetAny( const std::string & key,
const boost::any & value )
{
if ( key.empty() ) {
throw CAnyPropertyException( CAnyPropertyException::eEmptyKey);
}
virtual void Set( const std::string & key, const boost::any & /*value*/ )
{
throw CAnyPropertyException(CAnyPropertyException::eNoSet);
}
void CAnyHandlerEnv::Set( const std::string & key, const boost::any & value )
{
std::string env_value(key + "=" + boost::any_cast<std::string> (value));
int putenvReturn = ::putenv(const_cast<char*>(env_value.c_str()));
if (putenvReturn) { throw CAnyPropertyException(...); }
}
std::vector<SPhoneNumber> phoneVector;
...
m_values["phone"] = phoneVector;
}
Back End Real Life
class IConnection;
class CGPAttrHandlerBuildrunID : public CGPAttrHandlerBase
{
public:
virtual boost::any Get( const std::string & key ) const;
CGPAttrHandlerBuildrunID();
private:
void x_ConnectToDatabase();
int x_GetBuildID() const;
std::string x_ConstructSQL() const;
CGPipeProperty m_Environment;
std::string m_Database;
std::string m_Username;
std::string m_Password;
std::auto_ptr<IConnection> m_Connection;
};
Additional Applications
!
Heterogeneous Factory
!
Registry
Conclusions
!
No Magic Bullet
– Someone will have to cast
!
Helps Expose Clean Interfaces
– Even when internals are dirty
!
Glues OO and Generic Code
Acknowledgements
!
Mike Dicuccio
!
Andrei Alexandrescu
!
Kevlin Henney
!
Scott Meyers
!
Edvard Munch