Created
August 3, 2022 18:49
-
-
Save schaumb/770fb0fa018e1e6e031a011467769748 to your computer and use it in GitHub Desktop.
C++ interface dynamic implementation
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 <iostream> | |
#include <stdexcept> | |
template<typename T> | |
struct Mock { | |
void** mfptr = funptrs + 5; | |
void* funptrs[15] = {{}, {}, {}, {}, {}}; | |
static void throw_exc(void) { | |
throw std::runtime_error("Pure virtual function called"); | |
} | |
Mock() noexcept { | |
for (auto p = mfptr; p != funptrs + sizeof(funptrs) / sizeof(funptrs[0]); ++p) | |
*p = reinterpret_cast<void*>(&Mock::throw_exc); | |
} | |
template<typename U> | |
static unsigned int offset(U V) { | |
struct A { | |
virtual unsigned int _0(int) { return 0; } | |
virtual unsigned int _1(int) { return 1; } | |
virtual unsigned int _2(int) { return 2; } | |
virtual unsigned int _3(int) { return 3; } | |
virtual unsigned int _4(int) { return 4; } | |
virtual unsigned int _5(int) { return 5; } | |
virtual unsigned int _6(int) { return 6; } | |
virtual unsigned int _7(int) { return 7; } | |
virtual unsigned int _8(int) { return 8; } | |
virtual unsigned int _9(int) { return 9; } | |
}; | |
union { | |
U v0; | |
unsigned int (A:: *v1)(int); | |
} volatile offs{V}; | |
return (A{}.*offs.v1)(0); | |
} | |
template<typename U> | |
struct MFunToFun; | |
template<typename Res, typename ...Args> | |
struct MFunToFun<Res (T::* )(Args...) const> { | |
using fun_ptr = Res (*)(const T*, Args...); | |
}; | |
template<typename Res, typename ...Args> | |
struct MFunToFun<Res (T::*)(Args...)> { | |
using fun_ptr = Res (*)(T*, Args...); | |
}; | |
template<auto N> | |
Mock& set(typename MFunToFun<decltype(N)>::fun_ptr v) { | |
mfptr[offset(N)] = reinterpret_cast<void*>(v); | |
return *this; | |
} | |
template<typename MP> | |
Mock& set(MP val, typename MFunToFun<MP>::fun_ptr v) { | |
mfptr[offset(val)] = reinterpret_cast<void*>(v); | |
return *this; | |
} | |
T* operator ->() { | |
return std::launder(reinterpret_cast<T*>(this)); | |
} | |
operator T*() { | |
return operator->(); | |
} | |
operator T&() { | |
return *operator->(); | |
} | |
}; | |
struct IF { | |
virtual void first() = 0; | |
virtual int mult(int) const = 0; | |
virtual void asd() = 0; | |
virtual void asdsada() = 0; | |
virtual int getter() const = 0; | |
virtual ~IF() = default; | |
}; | |
int main() { | |
Mock<IF> m; | |
m.set(&IF::getter, [](const IF*) { return 42; }); | |
m.set<&IF::asd>([](IF* i) { | |
std::cout << "Here: asd " << i->getter() << " \n"; | |
}); | |
m.set<&IF::mult>([](const IF*, int p) { | |
std::cout << "Here: mult " << p << " \n"; return p*2; | |
}); | |
m->asd(); // use as pointer | |
IF& inf = m; // or as reference | |
std::cout << inf.mult(9) << std::endl; | |
try { | |
inf.first(); | |
} catch (const std::exception& ex) { | |
std::cout << "Exception catched: " << ex.what() << " \n"; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment