Skip to content

Instantly share code, notes, and snippets.

@alexeiz
Last active December 21, 2015 21:39
Show Gist options
  • Save alexeiz/6369486 to your computer and use it in GitHub Desktop.
Save alexeiz/6369486 to your computer and use it in GitHub Desktop.
interface_ptr
#include "interfaceptr.hpp"
#include <cassert>
struct Interface1 {};
struct Interface2 {};
struct Interface3 {};
struct Class1 : Interface1, Interface2 {};
struct Class2 : Interface2, Interface3 {};
void test_empty()
{
interface_ptr<Interface1> ip1;
interface_ptr<Interface1, Interface2> ip2;
}
void test_constructor()
{
// with one interface
interface_ptr<Interface1> ip1(new Class1());
// with two interfaces
interface_ptr<Interface1, Interface2> ip2(new Class1());
// implicit ctor
interface_ptr<Interface1, Interface2> ip3 = new Class1();
// brace-style ctor
interface_ptr<Interface1, Interface2> ip4{new Class1()};
// error: class doesn't implement one of the interfaces
// interface_ptr<Interface1, Interface2> iperr(new Class2());
}
void test_copy_ctor()
{
interface_ptr<Interface1, Interface2> ip1(new Class1());
interface_ptr<Interface1, Interface2> ip2(ip1);
interface_ptr<Interface1, Interface2> ip3 = ip1;
}
void test_assignment()
{
interface_ptr<Interface1, Interface2> ip1(new Class1());
interface_ptr<Interface1, Interface2> ip2;
ip2 = ip1;
}
void test_get()
{
Class1 * cl = new Class1();
interface_ptr<Interface1, Interface2> const ip(cl);
Interface1 * ip1 = get<Interface1>(ip);
assert(ip1 == cl);
Interface2 * ip2 = get<Interface2>(ip);
assert(ip2 == cl);
// error: interface not implemented
// Interface3 * ip3 = get<Interface3>(ip);
}
int main()
{
test_empty();
test_constructor();
test_copy_ctor();
test_assignment();
}
#ifndef INTEFACE_PTR_02028740704872
#define INTEFACE_PTR_02028740704872
#include <type_traits>
namespace detail
{
template <typename ...Ifaces>
struct interface_ptr_impl
{
template <typename T>
constexpr
interface_ptr_impl(T) {}
};
template <typename Iface, typename ...Ifaces>
struct interface_ptr_impl<Iface, Ifaces...>
: interface_ptr_impl<Ifaces...>
{
using base_type = interface_ptr_impl<Ifaces...>;
template <typename T>
constexpr
interface_ptr_impl(T ptr,
typename std::enable_if<std::is_base_of<Iface, typename std::remove_pointer<T>::type>::value
|| std::is_same<T, std::nullptr_t>::value>::type * = 0)
: base_type(ptr)
, ptr_(ptr)
{}
template <typename GetIface>
constexpr
GetIface * get(typename std::enable_if<std::is_same<GetIface, Iface>::value>::type * = 0) const
{
return ptr_;
}
template <typename GetIface>
constexpr
GetIface * get(typename std::enable_if<!std::is_same<GetIface, Iface>::value>::type * = 0) const
{
return base_type::template get<GetIface>();
}
Iface * ptr_;
};
} // namespace detail
template <typename ...Ifaces>
struct interface_ptr
: detail::interface_ptr_impl<Ifaces...>
{
using base_type = detail::interface_ptr_impl<Ifaces...>;
constexpr
interface_ptr()
: base_type(nullptr)
{}
template <typename T>
constexpr
interface_ptr(T * ptr)
: base_type(ptr)
{}
template <typename GetIface, typename ...GetIfaces>
friend
constexpr
GetIface * get(interface_ptr<GetIfaces...> const & obj)
{
return obj.base_type::template get<GetIface>();
}
};
#endif // INTEFACE_PTR_02028740704872
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment