I am writing a type-erased function wrapper similar to std::function
. (Yes, I have seen similar implementations and even the p0288r0 proposal, but my use-case is quite narrow and somewhat specialized.). The heavily simplified code below illustrates my current implementation:
class Func{
alignas(sizeof(void*)) char c[64]; //align to word boundary
struct base{
virtual void operator()() = 0;
virtual ~base(){}
};
template<typename T> struct derived : public base{
derived(T&& t) : callable(std::move(t)) {}
void operator()() override{ callable(); }
T callable;
};
public:
Func() = delete;
Func(const Func&) = delete;
template<typename F> //SFINAE constraints skipped for brevity
Func(F&& f){
static_assert(sizeof(derived<F>) <= sizeof(c), "");
new(c) derived<F>(std::forward<F>(f));
}
void operator () (){
return reinterpret_cast<base*>(c)->operator()(); //Warning
}
~Func(){
reinterpret_cast<base*>(c)->~base(); //Warning
}
};
Compiled, GCC 6.1 warns about strict-aliasing :
warning: dereferencing type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing]
return reinterpret_cast<T*>(c)->operator()();
I also know about the strict-aliasing rule. On the other hand, I currently do not know of a better way to make use of small object stack optimization. Despite the warnings, all my tests passes on GCC and Clang, (and an extra level of indirection prevents GCC's warning). My questions are:
- Will I eventually get burned ignoring the warning for this case?
- Is there a better way for in-place object creation?
See full example: Live on Coliru