передача указателя на встроенный тип, определенный на лету в Stack Overflow

Я хочу вызвать функцию библиотеки (которую я не могу изменить)

void function(int* i, char* c);

Есть ли способ вызвать функцию, определяющую int и char на лету?

то есть делать что-то вроде

function(&1, &'v');

вместо

int int_1 = 1;
char char_1 = 'v';
function(&int_1, &char_v);

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

4

Решение

Как отметили другие, ответ — нет …

Вы можете смоделировать это, перегружая function :

void function(int i, char c)
{
function(&i, &c);
}

Так что теперь вы можете написать function(1, 'v')

7

Другие решения

Почему вы хотите это сделать? Передача переменной в качестве неконстантного указателя указывает, что вызываемый объект намерен изменить передаваемый параметр, поэтому он не может быть значением.

Таким образом, передача указателя на литерал будет бессмысленной (если только это не строковый литерал, который отличается). Более того, поскольку это очевидно для вас, вы не можете определить адрес литерала, так как он не адресуемый. Единственная константа, которая может быть значимой, — это нулевой указатель или некоторый абсолютный адрес в адресуемой памяти.

3

Да, ты можешь.

function((int*)&(const int &)1, (char*)&(const char &)'v');

И это абсолютно законно, если после вызова функции указатели не разыменовываются. Это потому, что они имеют временное время жизни, равное полному выражению, в котором существует вызов функции.

Oни Можно использоваться функцией для изменения данных без каких-либо возможных проблем.

жизнь пример. Обратите внимание, что функция «функция» не определена. Пример только демонстрирует, что такой вызов функции полностью допустим.

Примечание. Сложность этого синтаксиса связана с некоторыми мерами безопасности C ++. В конце концов, передача указателя на неназванные данные — это то, что вы делаете редко. Однако это не означает, что эта структура является незаконной или UB.

2

Ответ FISOCPP хорош, но мне не нравится, как создается временный.

Это можно сделать с помощью сложного бокового синтаксиса:

function(&(int){1}, &(char){'v'});

Оба способа, которые используют временное действие, заставляют gcc выдавать предупреждения, когда вы пытаетесь получить адрес, хотя это совершенно определенный действительный код.

Интересно, что, поскольку составной латерал имеет автоматическое хранение в C, а скорее временное хранилище в C ++, поэтому не будет даже предупреждений при компиляции в режиме C99.

0

Вы можете сделать это в C ++ 11:

#include <type_traits>
#include <iostream>

template <typename Param, typename Arg>
Param take_address_if_necessary_impl (Arg&& arg, std::true_type, std::false_type)
{
return arg;
}

template <typename Param, typename Arg>
Param take_address_if_necessary_impl (Arg&& arg, std::false_type, std::true_type)
{
return &arg;
}

template <typename Param, typename Arg>
Param take_address_if_necessary (Arg&& arg)
{
return take_address_if_necessary_impl <Param> (
arg,
typename std::is_convertible <Arg, Param>::type {},
typename std::is_convertible <typename std::add_pointer <Arg>::type, Param>::type {}
);
}

template <typename Ret, typename... Params, typename... Args>
Ret call_special (Ret (*f) (Params...), Args&&... args)
{
return f (take_address_if_necessary <Params, Args> (args)...);
}

template <typename... Params, typename... Args>
void call_special (void (*f) (Params...), Args&&... args)
{
f (take_address_if_necessary <Params> (args)...);
}

void function (int* i, char* c)
{
std::cout << *i << ' ' << *c << std::endl;
}

int main ()
{
int i = 42;
char c = '%';

call_special (function, 1, 'f');
call_special (function, &i, '?');
call_special (function, &i, &c);
}

Вышеуказанная программа дает

1 f
42 ?
42 %

как и следовало ожидать.

Здесь есть несколько предостережений: во-первых, это потерпит неудачу, если вы попытаетесь использовать перегруженную функцию, потому что C ++ не может вывести перегруженную функцию на указатель на функцию:

void bar (int);
void bar (float);

call_special (bar, 3.0f); // Compiler error

Вы можете исправить это с помощью явных аргументов шаблона:

call_special <float> (bar, 3.0f); // Works

Или, конечно, явно введя функцию:

call_special ((void (*) (float))bar, 3.0f);

Во-вторых, для простоты, call_special и его помощники играют быстро и свободно с классами стоимости. Может потребоваться больше работы, чтобы иметь возможность надежно обрабатывать значения, константы и т. Д.

В-третьих, аргументы, которые можно передавать как значения, так и указатели, не будут работать. На самом деле, конверсии в целом, вероятно, вызовут головные боли:

void quux (long* i)
{
if (i)
std::cout << *i << std::endl;
else
std::cout << "(null)" << std::endl;
}

call_special (quux, NULL); // What does this print?

Возможно, вам лучше использовать функцию для явного захвата адреса:

template <typename T>
T* foo (T&& t)
{
return &t;
}

function (foo (3), foo ('7'));

Обратите внимание, что какой бы метод вы ни использовали, вы будете иметь дело с временными, которые умирают в точке с запятой. Таким образом, если используемая вами библиотека хранит ссылку на аргумент, который вы ей даете, у вас нет другого выбора, кроме как явно указать место хранения аргумента.

0

То, что может быть назначено или получено по его адресу, является lvalue.

То, что не может быть ни получено, ни назначено (sortof), является значением.

Это функция, которая принимает значение r и преобразует его в значение l. Это lvalue будет действительным только до тех пор, пока действительное значение rvalue было допустимым, что, надеюсь, достаточно долго:

template<class T>
T& as_lvalue(T&& t){return t;}
template<class T>
void as_lvalue(T&)=delete;

Затем мы используем его следующим образом:

function(&as_lvalue(1), &as_lvalue('v'));

as_lvalue примерно противоположная операция std::moveкоторый иначе можно было бы назвать as_rvalue, Это не совсем наоборот, потому что я сделал преобразование lvalue в lvalue, генерирующее ошибку.

Теперь одинарный & может быть перегружен. Итак, мы можем написать:

template<class T>
T* addressof_temporary(T&& t) {
return std::addressof( as_lvalue(std::forward<T>(t)) );
}

затем позвоните:

function(addressof_temporary(1), addressof_temporary('v'));

если параноик

0
По вопросам рекламы [email protected]