Is it possible to prevent array-to-pointer decay in arguments expanded from a parameter pack?
For example:
#include <iostream>
void foo() {
std::cout << "empty\n";
}
template <typename T, typename... Rest>
void foo(T &&t, Rest... rest) {
std::cout << "T, ...\n";
foo(rest...);
}
template <typename... Rest>
void foo(char *p, Rest... rest) {
std::cout << "char*, ...\n";
foo(rest...);
}
template <int N, typename... Rest>
void foo(char (&first)[N], Rest... rest) {
std::cout << "char[], ...\n";
foo(rest...);
}
int main() {
char a[2], b[2], c[2];
foo(a, b, c);
}
...outputs:
char[], ...
char*, ...
char*, ...
empty
As you can see, the first call goes to the array-based overload, but subsequent calls go to the pointer-based overload. Is there any way to get all of the calls to go to the array-based overload?
Related: Problems specializing variable template function
You want to pass the parameter pack by rvalue reference:
void foo(char (&first)[N], Rest&&... rest)
^^
So the code looks like this overall:
#include <iostream>
void foo() {
std::cout << "empty\n";
}
template <typename T, typename... Rest>
void foo(T &&t, Rest... rest) {
std::cout << "T, ...\n";
foo(rest...);
}
template <typename... Rest>
void foo(char *p, Rest... rest) {
std::cout << "char*, ...\n";
foo(rest...);
}
template <int N, typename... Rest>
void foo(char (&first)[N], Rest&&... rest) {
std::cout << "char[], ...\n";
foo(rest...);
}
int main() {
char a[2], b[2], c[2];
foo(a, b, c);
}
Giving the result:
char[], ...
char[], ...
char[], ...
empty
I haven't changed the other overloads to do the same, but you'd normally want them to use an rvalue reference as well (if they were actually being used).
Edit: As to why you'd want to do this/why it works: an rvalue reference can bind to either an rvalue or an lvalue. The crucial point we care about here is that when it binds to an lvalue, it remains an lvalue. In the case of an array, it retains its identity as an array, so what's received is an array.
When/if we pass an array by value, it undergoes the normal "decay" to a pointer, just like with a normal function.
For this specific case, we could also use a normal lvalue reference -- but if we did, that would not work for any type that wasn't an lvalue. For example, if we tried to call foo(1,2,3);, we'd get an error because an lvalue reference can't bind to 1, 2 or 3. To deal with that we could pass a const lvalue reference, but then we wouldn't be binding the reference directly to the rvalue -- we'd be creating a temporary containing a copy of the rvalue that was passed, and then binding the lvalue reference to that temporary copy instead. For the specific case of an int, that probably wouldn't be a major problem, but with something that was more expensive to copy (or if we wanted access to the original, not a copy) that could be a problem.
#JerryCoffin's answer hit the spot already, but I wanted add a small remark. You can separate the list processing code from the item one like this:
void foo_list() {
std::cout << "empty\n";
}
template <typename T, typename... Rest>
void foo_list(T &&t, Rest&&... rest) {
foo(t);
foo_list(rest...);
}
template <int N>
void foo(char (&t)[N]){
// ...
}
void foo(char *){
// ...
}
// etc...
(Maybe there's already an idiom for that?).
Related
see example below live : https://onlinegdb.com/Hkg6iQ3ZNI
#include <iostream>
#include <utility>
#include <type_traits>
class A
{
public:
A(int v=-10):v_(v){}
void print()
{
std::cout << "called A: " << v_ << std::endl;
}
private:
int v_;
};
void f(int v)
{
std::cout << "called f: " << v << std::endl;
}
template<typename T,typename ... Args>
void run(A&& a,
T&& t,
Args&& ... args)
{
a.print();
t(std::forward<Args>(args)...);
}
template<typename T,typename ... Args>
void run(T&& t,
Args&& ... args)
{
run(A(),
std::forward<T>(t),
std::forward<Args>(args)...);
}
int main()
{
int v_function=1;
int v_a = 2;
run(f,v_function);
return 0;
}
The code above compiles, runs and print (as expected):
called A: -10
called f: 1
but if the main function is modified to:
int main()
{
int v_function=1;
int v_a = 2;
run(f,v_function);
// !! added lines !!
A a(v_a);
run(a,f,v_function);
return 0;
}
then compilation fails with error:
main.cpp:30:6: error: no match for call to ‘(A) (void (&)(int), int&)’
t(std::forward(args)...);
~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~
which seems to indicate that even when an instance of A is passed as first argument, the overload function
void(*)(T&&,Args&&...)
is called, and not
void(*)(A&&,T&&,Args&&...)
With
template<typename T,typename ... Args>
void run(A&& a,
T&& t,
Args&& ... args)
a is not a forwarding reference, but an rvalue reference. That means when you do run(a,f,v_function); that function will not be selected because a is an lvalue and those can't be bound to rvalue references. There are two quick ways to fix this. First, use std::move on a like
run(std::move(a),f,v_function);
but this isn't great. a isn't actually moved in the function so you are kind of violating the principle of least surprise.
The second option is to make A in the function a template type so it becomes a forwarding reference and then you can constrain it to be of type A like
template<typename A_, typename T,typename ... Args, std::enable_if_t<std::is_same_v<std::decay_t<A_>, A>, bool> = true>
void run(A_&& a,
T&& t,
Args&& ... args)
{
a.print();
t(std::forward<Args>(args)...);
}
Your code works, if you are calling run with an rvalue.
Playable example here.
As NathanOliver already sad: void run(A&& a, T&& t, Args&& ... args) expects an rvalue reference.
Basic idea of an rvalue reference: You are passing an rvalue to a function (e.g. a string literal). That value will be copied to the function. This work is unnecessary. Instead, you are just "moving" the reference to that value, so that it is "owned" by a different part of your program. Move constructors are a good starting point for understanding this problem.
I'm trying to use an overloaded function to hide passing an int reference to a utility function when I don't care for the returned int data. Why is it that I need to use T& instead of T as the template argument? And why do I need the intermediate function that defines i as an rvalue?
class DataClass
{
};
template <typename T>
bool func(T& data, int& i) {
i = 1;
cout << "it worked!" << endl;
}
// I would like to remove this function
template <typename T>
bool func(T& data, int&& i) {
return func(std::forward<T&>(data), std::forward<int&>(i));
}
template <typename T>
bool func(T& data) {
// Why doesn't this line work?
// return func(std::forward<T>(data), std::forward<int>(0));
return func(std::forward<T&>(data), 0);
}
int main(int argc, char ** argv)
{
DataClass d;
func<DataClass>(d);
return 0;
}
You don't need std::forward at all here. Except for int&& i in the second overload, your parameters all declared as non-const lvalue references, so you can't pass an rvalue to any of them. And in the int&& overload, if you want to call the lvalue function from the rvalue function, you can just name the parameter i, because a name is always an lvalue.
template <typename T>
bool func(T& data, int& i) {
i = 1;
cout << "it worked!" << endl;
}
template <typename T>
bool func(T& data, int&& i) {
return func(data, i);
}
template <typename T>
bool func(T& data) {
return func(data, 0);
}
If you'd like to remove a function, note that it's actually the int& that does something effectively different: it changes i to 1. The rvalue overload technically also does, but something that has been passed as an rvalue should generally be ignored after that point, so callers should only count on func(T&, int&&) to print the message to cout. And to take an int that isn't an lvalue... just take an int.
template <typename T>
bool func(T& data, int& i) {
i = 1;
cout << "it worked!" << endl;
}
template <typename T>
bool func(T& data, int i=0) {
return func(data, i); // effect on i is ignored.
}
// Okay to pass a const int?
template <typename T>
bool func(T&, const volatile int&&) = delete;
That third deleted template preserves one behavior of your original code, though it's not clear if you actually want that behavior or not. In the function
void test() {
DataClass d;
const int n = 5;
func(d, n);
}
... the original code would have failed to compile, since a const int lvalue can't bind to either int& or int&&. But the change to a parameter of simply int would allow this test to compile, by making a copy of n to be the plain int parameter. Then the change to that int i just gets discarded, even though you gave n to the function. The deleted template is a better match for the const int lvalue n, so it would cause test to fail to compile. If you do want the behavior where func(d, n) is valid but has no effect on n, just take out that deleted template.
I want to call a function of a library (that I can not modify)
void function(int* i, char* c);
Is there a way to call the function defining the int and the char on the fly?
i.e. doing something like
function(&1, &'v');
instead of
int int_1 = 1;
char char_1 = 'v';
function(&int_1, &char_v);
This would enormously decrease the length of my code while increasing readability.
As others have noted, the answer is no...
You could simulate it by overloading function :
void function(int i, char c)
{
function(&i, &c);
}
So now you can write function(1, 'v')
Why would you want to do so? Passing a variable as a non const pointer indicates that the callee intends to modify the parameter that is passed therefore it cannot be an rvalue.
So passing a pointer to a literal would be meaningless (unless it is a string literal which is different). Moreover as it is obvious to you, you cannot determine an address of a literal as it is not addressable. The only constant that could be meaningful is a null pointer or some absolute address to an addressable memory
Yes - you can.
function((int*)&(const int &)1, (char*)&(const char &)'v');
And it's completely legal as long as the pointers aren't dereferenced after the function call. This is because they have temporary life-time which equals the full expression in which the function call exists.
They can be used by the function to modify the data without any possible issues.
Life example. Note that the function 'function' isn't defined. The example only demonstrates that such function call is completely valid.
Note: The complexity of this syntax is due to some 'C++' security measures. After all passing a pointer to unnamed data is something you do rare. However this doesn't mean that this structure is illegal or UB.
FISOCPP's answer is nice, but I don't like the way temporary is created.
It can be done this way with compound lateral syntax:
function(&(int){1}, &(char){'v'});
Both ways that uses temporary cause gcc to emit warnings when you try to take the address, although it's perfectly defined valid code.
Interestingly, as compound lateral has automatic storage in C rather temporary storage in C++, so there won't be even warnings if compiled in C99 mode.
You can make this happen in 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);
}
The above program yields
1 f
42 ?
42 %
as you'd expect.
There are some caveats here: first, this will fail if you try to use an overloaded function, because C++ can't deduce an overloaded function to a function pointer:
void bar (int);
void bar (float);
call_special (bar, 3.0f); // Compiler error
You might be able to fix this with explicit template arguments:
call_special <float> (bar, 3.0f); // Works
Or of course explicitly typing the function:
call_special ((void (*) (float))bar, 3.0f);
Second, for simplicity's sake, call_special and its helpers play fast and loose with value classes. It may need more work to be able to handle rvalues, const values, etc. robustly.
Third, arguments that can be passed both as values and as pointers will not work. In fact, conversions in general are probably going to cause headaches:
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?
You may be better off using a function to grab the address explicitly:
template <typename T>
T* foo (T&& t)
{
return &t;
}
function (foo (3), foo ('7'));
Note that whatever method you use, you're going to be dealing with temporaries, which die at the semicolon. So if the library you're using stores a reference to an argument you give it, you have no choice but to explicitly give storage to the argument.
Something that can be assigned to or have its address taken is an lvalue.
Something that cannot have its address taken, nor be assigned to (sortof), is an rvalue.
This is a function that takes an rvalue, and converts it to an lvalue. This lvalue will only be valid as long as the source rvalue was valid, which hopefully is long enough:
template<class T>
T& as_lvalue(T&& t){return t;}
template<class T>
void as_lvalue(T&)=delete;
We then use it as follows:
function(&as_lvalue(1), &as_lvalue('v'));
as_lvalue is roughly the opposite operation of std::move, which could otherwise be called as_rvalue. It isn't completely the opposite, because I made lvalue-to-lvalue conversion generate an error.
Now, unary & can be overloaded. So we can write:
template<class T>
T* addressof_temporary(T&& t) {
return std::addressof( as_lvalue(std::forward<T>(t)) );
}
then call:
function(addressof_temporary(1), addressof_temporary('v'));
if paranoid.
(This question follows from this answer)
I am trying to adapt a trampoline function that is currently just passing through a variable number of arguments.
I would like to have it convert any argument PyObject* pyob to Object{pyob}, but forward all other arguments through.
So (void* self, int, PyObject*, float) -> (int, Object, float)
In that example, the first self argument is stripped away. This always happens. Out of the remaining arguments, one of them is of type PyObject*, and hence requires conversion to Object.
Here is the function:
template <typename T, T t>
struct trap;
template <typename R, typename... Args, R(Base::*t)(Args...)>
struct trap<R(Base::*)(Args...), t>
{
static R
call(void* s, Args... args)
{
std::cout << "trap:" << typeid(t).name() << std::endl;
try
{
return (get_base(s)->*t)(std::forward<Args>(args)...);
}
catch (...)
{
std::cout << "CAUGHT" << std::endl;
return std::is_integral<R>::value ? static_cast<R>(-42) : static_cast<R>(-3.14);
}
}
};
It appears not to be forwarding arguments. I think it is making a copy of each argument. I've tried:
call(void* s, Args&&... args)
But that just generates compiler errors.
The complete test case is here
How can I fix the function to perfect-forward all arguments apart from those of type PyObject*, which it should convert?
It appears not to be forwarding arguments
You can't perfectly-forward arguments of a function which is not a template, or which is invoked through a pointer to a function, like you do. Perfect-forwarding involves a template argument deduction, which doesn't take place when you invoke a function through a pointer - that pointer points to a concrete instantiation of a function template.
The std::forward<Args>(args) expression is there to possibly utilize a move-constructor to copy-initialize the parameters of the target function from those arguments of call that are passed by value (or by a hard-coded rvalue reference), or let them be bound by an rvalue reference - you won't need any more those instances, you are free to move-from them, saving at least one copy operation. (It could be as simple as static_cast<Args&&>(args)..., because it's just a reference collapsing).
I would like to have it convert any argument PyObject* pyob to Object{pyob}, but forward all other arguments through. How can I fix the function to perfect-forward all arguments apart from those of type PyObject*, which it should convert?
#include <utility>
template <typename T, typename U>
T&& forward_convert(U&& u)
{
return std::forward<T>(std::forward<U>(u));
}
template <typename T>
Object forward_convert(PyObject* a)
{
return Object{a};
}
// ...
return (get_base(s)->*t)(forward_convert<Args>(args)...);
To replace any occurrence of Object with PyObject* while creating the signature of call function, and only then conditionally forward or convert the arguments, you should do what follows:
template <typename T>
struct replace { using type = T; };
template <>
struct replace<Object> { using type = PyObject*; };
// you may probably want some more cv-ref specializations:
//template <>
//struct replace<Object&> { using type = PyObject*; };
template <typename T, T t>
struct trap;
template <typename R, typename... Args, R(Base::*t)(Args...)>
struct trap<R(Base::*)(Args...), t>
{
static R
call(void* s, typename replace<Args>::type... args)
{
try
{
return (get_base(s)->*t)(forward_convert<typename replace<Args>::type>(args)...);
}
catch (...)
{
return std::is_integral<R>::value ? static_cast<R>(-42) : static_cast<R>(-3.14);
}
}
};
DEMO
You have to change call to (Note that I introduce Ts in addition to Args).
template <typename ... Ts>
static R
call(void* s, Ts&&... args)
{
std::cout << "trap:" << typeid(t).name() << std::endl;
try
{
return (get_base(s)->*t)(std::forward<Ts>(args)...);
}
catch (...)
{
std::cout << "CAUGHT" << std::endl;
return std::is_integral<R>::value ? static_cast<R>(-42) : static_cast<R>(-3.14);
}
}
I have the following problem. Say you want to write a generic function that can take a lambda expression. I understand that if the parameter is of type std::function, then I could not only use lambdas, but also functions and even pointers to functions. So at a first step, I did the following:
void print(std::function<void(int, int)> fn) {
fn(1,2);
}
int main() {
print([](int i, int j) { std::cout << j <<','<<i<<'\n'; });
return 0;
}
Now the problem is that I want to make this function generic, meaning that I don't want the lambda expression to have only two parameters.
So I tried changing the signature of the print function to something more generic like:
template <class function_type>
void print(function_type fn);
But now the problem is that the function takes ANY object and I'm not ok with that.
But the main problem is that, I have no idea how many parameters the object fn can accept.
So in a way I'm looking for a compile time way to determine how many arguments fn has, and if possible to change the type of fn to std::function. And then, given that I know the number of parameters that fn accepts, is there a generic way to pack an arbitrary number of parameters to be passed to fn? I don't even know if this is possible within C++11. What I mean is that given the number of arguments, is there a way to pack parameters to pass to fn? So that if there are two arguments, then I would call
fn(arg1, arg2);
if there are three:
fn(arg1, arg2, arg3);
and so on.
Thank you all for your insight.
aa
The following snippets might be useful.
This gives the number of arguments that a std::function takes
template <typename Signature>
struct count_args;
template <typename Ret, typename... Args>
struct count_args<std::function<Ret(Args...)>> {
static constexpr size_t value = sizeof...(Args);
};
For example the following code compiles (clang 3.2, gcc 4.7.2 and icc 13.1.0)
static_assert(count_args<std::function<void() >>::value == 0, "Ops!");
static_assert(count_args<std::function<void(int) >>::value == 1, "Ops!");
static_assert(count_args<std::function<void(int, int)>>::value == 2, "Ops!");
As far as I understand, you want to call the function object passing the correct number of arguments, right? Then for each argument we need to provide a value which is convertible to its type. A solution with this generality is very hard (or even impossible). Hence, I'll present two alternatives.
1 Each argument is a value initialized object of its type. (This is what ecatmur suggested.)
template <typename Ret, typename... Args>
Ret call(const std::function<Ret(Args...)>& f) {
return f(Args{}...); // for the intel compiler replace {} with ()
}
2 A fixed value is given and all the arguments are implicitly initialized from this value:
template <typename Ret, typename... Args, typename Val, typename... Vals>
typename std::enable_if<sizeof...(Args) == sizeof...(Vals), Ret>::type
call(const std::function<Ret(Args...)>& f, const Val&, const Vals&... vals) {
return f(vals...);
}
template <typename Ret, typename... Args, typename Val, typename... Vals>
typename std::enable_if<(sizeof...(Args) > sizeof...(Vals)), Ret>::type
call(const std::function<Ret(Args...)>& f, const Val& val, const Vals&... vals) {
return call(f, val, val, vals...);
}
The three overloads are unambiguous and can be used as the following examples show:
{
std::function<char()> f = []() -> char {
std::cout << "f() ";
return 'A';
};
std::cout << call(f) << std::endl; // calls f()
std::cout << call(f, 0) << std::endl; // calls f()
}
{
std::function<char(int)> f = [](int i) -> char {
std::cout << "f(" << i << ") ";
return 'B';
};
std::cout << call(f) << std::endl; // calls f(0)
std::cout << call(f, 1) << std::endl; // calls f(1)
}
{
std::function<char(int, int)> f = [](int i, int j) -> char {
std::cout << "f(" << i << "," << j << ") ";
return 'C';
};
std::cout << call(f) << std::endl; // calls f(0, 0)
std::cout << call(f, 2) << std::endl; // calls f(2, 2)
}
Yes you can pack as many parameters to fn as you wish using variadic templates.
template <class function_type, class... Args>
void print(function_type fn, Args... args)
{
//Call fn with args
fn(std::forward<Args>(args...));
}
To find out how many args there are in the parameter pack, you can use sizeof...(args).
To determine the signature of a callable, you can use the solution from Inferring the call signature of a lambda or arbitrary callable for "make_function". You can then package the callable into a std::function, or create a tag and use parameter inference:
template<typename T> struct tag {};
template<typename F, typename... Args>
void print_impl(F &&fn, tag<void(Args...)>) {
fn(Args{}...);
}
template<typename F>
void print(F &&fn) {
print_impl(std::forward<F>(fn), tag<get_signature<F>>{});
}
Note this uses value-initialised arguments; if you want anything more complex you can build a std::tuple<Args...> and pass that along, invoking it per "unpacking" a tuple to call a matching function pointer.