Вызов функции по ее адресу через шаблонную функцию

Предполагая, что у меня есть адрес памяти времени выполнения функции в приложении, и я знаю тип возвращаемого значения указанной функции, можно ли вызвать функцию, зная тип возвращаемого значения функции, ее аргументы и соглашение о вызовах, используя вариативный шаблон?

Шаблонная функция должна поддерживать возвращаемые типы как void, так и non-void. Из-за того, что мы имеем дело с указателями на функции, компилятор не должен жаловаться, несмотря на return ptr.

Я думал сделать что-то вроде этого:

template<typename ReturnType, typename Address, typename... Args>
ReturnType function_caller(Address address, Args... args)
{
    ReturnType(*ptr)(Args...) = address;
    return ptr(args...);
}
int main()
{
    auto address = 0x100;
    auto address2 = 0x200;
    function_caller<void>(&address, 1, 1); // Function with return type void.
    int result = function_caller<int>(&address2, 1, 2, 3.f, "hello"); 
    // result should contain the int value we received by calling the function at 0x200

}

К сожалению, компилятор выдает ошибку C2440: он не может преобразовать адрес address в 'ReturnType (__cdecl *)(int,int)'

Я был бы очень признателен за вашу помощь с этой проблемой. Я знаю, что мог бы просто разделить эту оболочку на 2 функции: одну для вызовов void и одну для вызовов non-void, но я надеюсь, что есть более элегантное решение с поддержкой шаблонов.

Спасибо и хорошего дня!


person Troganda    schedule 25.08.2020    source источник
comment
Да, я знаю, адреса не настоящие адреса и просто для того, чтобы показать концепцию. Это не код, который я бы использовал во время выполнения. Пожалуйста, просто предположим, что адрес правильный. Кроме того, компилятор не будет возражать, поскольку это ошибка времени выполнения, а не времени компиляции.   -  person Troganda    schedule 25.08.2020
comment
Автоматический вывод параметров также опасен. Это четвертый параметр const char* или const char[6]? Я почти уверен, что это последнее.   -  person Mooing Duck    schedule 25.08.2020
comment
Если вы хотите иметь странный синтаксис для вызовов void, вы также можете уговорить его вывести типы возвращаемых значений. coliru.stacked-crooked.com/a/42c1c60bf0e2f50a   -  person Mooing Duck    schedule 25.08.2020


Ответы (1)


ответ да, но делать это с вариативным шаблоном опасно.

чтобы заставить компилятор привести адрес к указателю на функцию, вам нужно использовать reinterpret_cast или c cast .

примечание: вы неправильно приводите целочисленный адрес к указателю, потому что на самом деле вы пытаетесь привести адрес переменной, содержащей адрес, к указателю, а не к самому адресу!

поэтому эта строка:

function_caller<void>(&address, 1, 1); // Function with return type void.

должно быть :

function_caller<void>(address, 1, 1); // Function with return type void.

и всегда используйте тип адреса uintptr_t, который подходит для любого адреса, доступного для архитектуры (64-битный или 32-битный)

но делать это с вариативным шаблоном совсем небезопасно. причина в том, что функция имеет определенный тип аргументов, например:

int fn(std::string& str, const char* ptr, uint64_t& i);

но когда вы используете вариативный шаблон, компилятор выведет типы из переданных аргументов, однако могут потребоваться некоторые преобразования!

поэтому в вашей текущей версии:

int i;
function_caller<int>(0x15216516, "str", "ptr", i);

компиляция будет предполагать, что сигнатура функции выглядит примерно так:

int fn(const char*, const char*, int); // wrong types means stack corruptions and undefined behaviors

также см. это:

std::string to_string(std::string_view v);

function_caller<std::string>(0x15216516, "str"); // wrong the compiler won't convert the string literal for you and the function will end up with a dangling view

function_caller<std::string>(0x15216516, std::string("str")); // wrong again there is no conversion from std::string to std::string_view here

так что действительно надежно только указать весь тип функции и использовать его для приведения адреса, как это делает boost.dll

person dev65    schedule 25.08.2020
comment
Нет, два параметра будут const char[4], а не const char* - person Mooing Duck; 25.08.2020