Итак, у меня есть вариантный класс, в который я недавно добавил возможность хранить данные указателя на функцию-член. Для этого используется следующий код.
class Variant
{
void* _value;
template <typename T1>
void Variant::ThisCall( T1* pThis )
{
typedef void(T1::* fptr)( );
fptr a;
int* iiVal = new (&a) int;
*iiVal = *((int*)_value);
(pThis->*a)( );
}
};
// usage
Variant myfunc = &SomeClass::SomeMethod;
SomeClass* s = new SomeClass( );
myfunc.ThisCall( s );
Самое важное, над чем мне приходилось работать в этом решении, это то, что функции указателя на член не могут быть приведены к типу void*. Таким образом, оператор присваивания по существу выполняет обратную операцию. Он берет заданные данные, маскирует их как указатель int (если это сам указатель) и назначает указатель int на void*, что вполне допустимо.
Итак, мой вопрос заключается в следующем: Почему мне кажется, что это ужасное решение проблемы? Мне кажется, что это такой большой взлом, что с ним должны быть серьезные проблемы, но я Я так глубоко погрузился в эту проблему в течение нескольких дней, что не могу заглянуть за нее. Спасибо!
[ИЗМЕНИТЬ №1]
Один комментатор отметил, что это может не работать с виртуальными методами. Я протестировал, используя следующий код, и, похоже, он проверил.
class ImplA : public Base
{
public:
virtual void Print( )
{
cout << "ImplA print\n";
}
};
class ImplB : public Base
{
public:
virtual void Print( )
{
cout << "ImplB print\n";
}
};
class ImplC : public ImplA
{
public:
virtual void Print( )
{
cout << "ImplC print\n";
}
};
// usage
Variant x = &Base::Print;
auto b = new ImplA; // replace ImplA with ImplB or ImplC and it works as expected
x.ThisCall( b );
Для получения дополнительной информации я использую VS2010 в качестве компилятора. Спасибо!
[ИЗМЕНИТЬ № 2]
Чтобы обеспечить контекст, я уже некоторое время работаю над этим вариантом класса и пытаюсь заставить его поддерживать все, что вы можете ему предложить. При этом я подумал об указателях на функции и указателях на функции-члены. Затем я придумал это и задался вопросом, насколько надежно это решение на самом деле. Кастинг и синтаксис были для меня первым красным флажком, но я решил, что из-за разброса данных, которые они содержат, это просто приходит с территорией. Но я все еще не уверен, что это должно работать именно так.
void*не обязательно должен иметь тот же размер, что и любой указатель функции IIRC. - person dyp   schedule 10.12.2013void*, однако это неверно, например, для g++. Даже если бы это было так, вы нарушаете правило алиасинга [basic.lval]/10. - person dyp   schedule 10.12.2013