Я пишу обертку с стиранием типа, похожую на std::function
. (Да, я видел подобные реализации и даже предложение p0288r0, но мой прецедент довольно узкий и несколько специализированный.). Сильно упрощенный код ниже иллюстрирует мою текущую реализацию:
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
}
};
Скомпилировано, GCC 6.1 предупреждает о strict-aliasing:
warning: dereferencing type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing]
return reinterpret_cast<T*>(c)->operator()();
Я также знаю правило строгого сглаживания. С другой стороны, я в настоящее время не знаю, как лучше использовать оптимизацию стека небольших объектов. Несмотря на предупреждения, все мои тесты проходят на GCC и Clang (и дополнительный уровень косвенности предотвращает предупреждение GCC). Мои вопросы:
- В конечном итоге я сожгусь, игнорируя предупреждение для этого случая?
- Есть ли лучший способ создания объектов на месте?
Смотрите полный пример: Live on Coliru