Skip to content

Instantly share code, notes, and snippets.

@rianhunter
Last active August 29, 2015 14:27
Show Gist options
  • Save rianhunter/d27853a57dba9dca7baa to your computer and use it in GitHub Desktop.
Save rianhunter/d27853a57dba9dca7baa to your computer and use it in GitHub Desktop.
Translation of Go's implementation of interfaces to C++11
// this is the header that does all the heavy-lifting
// NB: lots of boilerplate
// runtime function table
struct FrobableTable {
int (*frob)(const void *ptr);
};
// forward declaration of the implementation
template<class FrobableImplType>
struct FrobableImpl {
static int frob(const FrobableImplType &);
};
// helper template that statically generates
// frobable function pointers for the function table
template<class FrobableImplType>
struct FrobableFns {
static int frob(const void *ptr) {
return FrobableImpl<FrobableImplType>::frob(*static_cast<const FrobableImplType *>(ptr));
}
static FrobableTable gen_frobable_table() {
return {
&frob,
};
}
};
// singleton map from frobable implemenation type to function table
template<class FrobableImpl>
FrobableTable __frobable_fns = FrobableFns<FrobableImpl>::gen_frobable_table();
// mimics a go polymorphic interface pointer
class Frobable {
// two pointers, one to the data and one to the function table
void *_ptr;
FrobableTable *_fn_table;
public:
template<class FrobableImpl>
Frobable(FrobableImpl & obj)
: _ptr(&obj)
, _fn_table(&__frobable_fns<FrobableImpl>)
{}
int frob() const {
return _fn_table->frob(_ptr);
}
};
// implementation file of example consumer of interfaces
#include "frobable.hpp"
int frobber(Frobable p) {
return p.frob() + 1;
}
// header declaration for type sthat will implement the interface
// my frobable thing, no need to inherit
class MyFrob {
};
// another frobable thing, no need to inherit
class MyOtherFrob {
};
// separate source file where we implement
// the frobable methods for each frob-type
#include "frobable.hpp"
#include "frobs.hpp"
template<>
int FrobableImpl<MyFrob>::frob(const MyFrob &) {
return 1;
}
template<>
int FrobableImpl<MyOtherFrob>::frob(const MyOtherFrob &) {
return 2;
}
#include "frobable.hpp"
#include "frobs.hpp"
// forward declaration
int frobber(Frobable p);
int main() {
MyFrob a;
MyOtherFrob b;
// MyFrob and MyOtherFrob objecs can be used as a frobable
// use implementation from other source file
return frobber(a) + frobber(b);
}
/* output of: c++ -std=c++14 -O3 -flto frobber.cpp main.cpp frobs_impl.cpp
0000000100000ee0 <_main>:
100000ee0: 55 push %rbp
100000ee1: 48 89 e5 mov %rsp,%rbp
100000ee4: 53 push %rbx
100000ee5: 48 83 ec 18 sub $0x18,%rsp
100000ee9: 48 8d 7d f0 lea -0x10(%rbp),%rdi
100000eed: ff 15 d 01 00 00 callq *0x11d(%rip) # 100001010 <__frobable_fns<MyFrob>>
100000ef3: 89 c3 mov %eax,%ebx
100000ef5: 48 8d 7d e8 lea -0x18(%rbp),%rdi
100000ef9: ff 15 21 01 00 00 callq *0x121(%rip) # 100001020 <__frobable_fns<MyOtherFrob>>
100000eff: 8d 44 18 02 lea 0x2(%rax,%rbx,1),%eax
100000f03: 48 83 c4 18 add $0x18,%rsp
100000f07: 5b pop %rbx
100000f08: 5d pop %rbp
100000f09: c3 retq
100000f0a: 66 0f f 44 00 00 nopw 0x0(%rax,%rax,1)
0000000100000f10 <FrobableFns<MyFrob>::frob(void const*)>:
100000f10: 55 push %rbp
100000f11: 48 89 e5 mov %rsp,%rbp
100000f14: b8 01 00 00 00 mov $0x1,%eax
100000f19: 5d pop %rbp
100000f1a: c3 retq
100000f1b: 0f f 44 00 00 nopl 0x0(%rax,%rax,1)
0000000100000f20 <FrobableFns<MyOtherFrob>::frob(void const*)>:
100000f20: 55 push %rbp
100000f21: 48 89 e5 mov %rsp,%rbp
100000f24: b8 02 00 00 00 mov $0x2,%eax
100000f29: 5d pop %rbp
100000f2a: c3 retq
100000f2b: 90 nop
100000f2c: 90 nop
100000f2d: 90 nop
100000f2e: 90 nop
100000f2f: 90 nop
*/
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment