Last active
August 29, 2015 14:27
-
-
Save rianhunter/d27853a57dba9dca7baa to your computer and use it in GitHub Desktop.
Translation of Go's implementation of interfaces to C++11
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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); | |
} | |
}; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// implementation file of example consumer of interfaces | |
#include "frobable.hpp" | |
int frobber(Frobable p) { | |
return p.frob() + 1; | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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 { | |
}; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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; | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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