Skip to content

Instantly share code, notes, and snippets.

@alexeiz
Last active December 21, 2015 16:59
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save alexeiz/019f31a948df86542559 to your computer and use it in GitHub Desktop.
Save alexeiz/019f31a948df86542559 to your computer and use it in GitHub Desktop.
interface_ptr : generic pointer/handle class that holds a pointer to an object and ensured that it implements specified interfaces.
#include <type_traits>
template <typename Derived, typename ...Bases>
struct is_derived_from;
template <typename Derived, typename Base, typename ...Bases>
struct is_derived_from<Derived, Base, Bases...>
: std::integral_constant<bool,
std::is_base_of<Base, Derived>::value
&& is_derived_from<Derived, Bases...>::value>
{};
template <typename Derived, typename Base>
struct is_derived_from<Derived, Base> : std::is_base_of<Base, Derived>
{};
template <typename Test, typename ...Types>
struct is_one_of;
template <typename Test, typename Type, typename ...Types>
struct is_one_of<Test, Type, Types...>
: std::integral_constant<bool,
std::is_same<Test, Type>::value
|| is_one_of<Test, Types...>::value>
{};
template <typename Test, typename Type>
struct is_one_of<Test, Type> : std::is_same<Test, Type>
{};
template <typename ...Ifaces>
class interface_ptr;
template <typename Iface, typename ...Ifaces>
class interface_ptr<Iface, Ifaces...>
{
public:
template <typename T>
interface_ptr(T * ptr,
typename std::enable_if<is_derived_from<T, Iface, Ifaces...>::value>::type * = 0)
: ptr_(ptr)
{}
private:
Iface * ptr_;
template <typename GetIface, typename ...GetIfaces>
friend
GetIface * get_iface(interface_ptr<GetIfaces...> obj,
typename std::enable_if<is_one_of<GetIface, GetIfaces...>::value>::type * = 0)
{
return dynamic_cast<GetIface *>(obj.ptr_);
}
};
struct Interface1 { virtual ~Interface1() {} };
struct Interface2 { virtual ~Interface2() {} };
struct Interface3 { virtual ~Interface3() {} };
struct Concrete1 : Interface1, Interface2, Interface3 {};
struct Concrete2 : Interface1, Interface2 {};
struct Concrete3 : Interface1, Interface3 {};
int main()
{
interface_ptr<Interface1, Interface2> ip1 = new Concrete2();
// error: Concrete3 doesn't implement Interface2
// interface_ptr<Interface1, Interface2> ip2 = new Concrete3();
Interface2 * if2 = get_iface<Interface2>(ip1);
// error: ip1 doesn't contain a pointer implementing Interface3
// Interface3 * if3 = get_iface<Interface3>(ip1);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment