1

I really want to pass a variable that is auto (function) as input in another function.

Here is a structure that receives parameters for my xroot f:

struct my_f_params { 
    double flag; 
    auto inter_auto(double x, double y);
};

Here is the function I essentially want to have (it's based on a GSL library, so the form can't be changed). I want to be able to pass a "function" as a variable, and the only way I guessed it would happen is with auto.

After passing it, I try storing it to a new auto, But I get an error (see below):

double xrootf (double x, void * p)
{
    my_f_params * params = (my_f_params *)p;
    double flag = (params->flag);
    auto inter_auto = (params->inter_auto);    
    return flag*inter_auto(x);
}

Here is an auto function that returns an auto function. This works perfectly (if xrootf is commented, I can print for example new_f(2)(2), etc):

auto new_f(double x){
    auto in_result = [](double x, double y){
        return x*y;
    };

    using namespace std::placeholders;
    auto result_f = std::bind(in_result,x,_1);
    
    return result_f;
}

The test code that proves that the auto function new_f is working good:

int main(int argc, char const *argv[])
{
    auto nest_f = new_f(-0.5);
    printf("%f\n", nest_f(+2));
    return 0;
} 

Recasting the auto function to double is not working, either (for the struct part of the code).

The error I'm getting is:

auto_pass.cpp: In function 'double xrootf(double, void*)':
auto_pass.cpp:28:42: error: unable to deduce 'auto' from 'params->my_f_params::inter_auto'
28 |     auto inter_auto = (params->inter_auto);
   |                                          ^
auto_pass.cpp:28:42: note:   couldn't deduce template parameter 'auto'

The aim of the code is this:

  1. Have a function that is able to return a function (DONE W/ new_f)

  2. Have a function that is able to take a function as a variable (the one with new_f) (Not Done)

EDIT: Here's a quick Python script that's very easy to achieve what I'm saying:

def new_f(y):
    #make any number of computatioanly costly Algebra with y
    def g(x):
        return x*y
    return g
def xroot(f,flag):
    return flag-f(flag)
Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
Billy Matlock
  • 340
  • 2
  • 14
  • This looks more C-- than C++. – Enlico Mar 17 '21 at 15:21
  • function 'inter_auto' with deduced return type cannot be used before it is defined. – 273K Mar 17 '21 at 15:25
  • 2
    `auto` is just a placehold for the actual type infered from the initializer, there arent variables of type `auto`. – 463035818_is_not_an_ai Mar 17 '21 at 15:31
  • @Enlico Ok sorry, It's my 4th day on Cpp and I'm a more into Physics. No need to be sarcastic – Billy Matlock Mar 17 '21 at 15:36
  • @BillyMatlock, to be less sarcastic, the way you crafted the question is not conformant to [_how-to-ask_](https://stackoverflow.com/help/how-to-ask). For instance, you've technically just thrown a code on the page, with your explanation being merely _pass a variable that is Auto (Function) as input in another function_ which is insufficient and incorrect. – Enlico Mar 17 '21 at 15:40
  • @largest_prime_is_463035818 Yeah but for example I can call `nest_f(2)` and it will print it correctly. Even though I know it's double, I can't recast `nest_f` as a double as to pass it to my function `xroot_f` – Billy Matlock Mar 17 '21 at 15:40
  • i dont understand what the code is supposed to do either. Do you not have a definition for hte method `inter_auto` ? What is the line `auto inter_auto = (params->inter_auto);` supposed to mean? – 463035818_is_not_an_ai Mar 17 '21 at 15:47
  • @Enlico You are right. I'm sorry. I tried to explain evrything I write with last edit. Also this is not the part of code I used, so I tried to make a MWE just to post it here, for it to be clear enough. So its not that I didnt try to post the question as clear as I could – Billy Matlock Mar 17 '21 at 15:48
  • can you try to explain what you are trying to do without using the word auto? Its kinda confusing because I don't understand what you mean with "auto function". Is it possible that you want `my_f_params` to be a structure that holds two member variables that you can pass to some other function? It isnt. Its a structure with one member variable and one member fucntion that you declared but did not define. There is no way to deduce the return type of `auto inter_auto(double x, double y);` without its definition – 463035818_is_not_an_ai Mar 17 '21 at 15:51
  • @largest_prime_is_463035818 You are right. Really sorry. Edited the question. Didnt want to be vague. The aim of the code is this: 1) Have a function that is able to return a function (DONE W/ new_f) 2) Have a function that is able to take a function as a variable (the one with new_f) (Not Done) `auto inter_auto = (params->inter_auto); ` is an `auto` variable to append the `params->inter_auto` function as the input of `xrootf` suggests – Billy Matlock Mar 17 '21 at 15:53
  • what is `params->inter_auto` ? You declared it but you didnt define the method – 463035818_is_not_an_ai Mar 17 '21 at 15:55
  • `new_f` can be written as `auto new_f(double x){ return [x](double y) { return x*y;}; }`. You do not need `bind` here. If you want to return a callable that takes a single parameter then just return a callable that takes a single parameter instead of first creating one with two parameters and then binding one of them. The capture of the lambda is the much easier alternative comared to `bind`. – 463035818_is_not_an_ai Mar 17 '21 at 15:59
  • @largest_prime_is_463035818 Ok, sorry again. I wrote on the Question what I want to achieve with this MWE. And thank you for your time, honestly. I want to have a `function` that gets the result of `new_f` as a variable. <-. THe part of the code `params->inter_auto` is confusing but I just want to pass `inter_auto` variable (that came from new_f) to the function namespace as a new "`variabe`" – Billy Matlock Mar 17 '21 at 16:00
  • `my_f_params::inter_auto` is not a member variable, it is a member function (without definition). – 463035818_is_not_an_ai Mar 17 '21 at 16:02
  • @largest_prime_is_463035818 You said "just return a callable that takes a single parameter instead of first creating one with two parameters and then binding one of them." Thats basically a function right? I mean it gets one parameter, I thought the only way of doing that is through auto and bind – Billy Matlock Mar 17 '21 at 16:03
  • still not sure, but I still believe that you think you can store some parameters in `my_f_params`, a `double` and a function, but you cant – 463035818_is_not_an_ai Mar 17 '21 at 16:03
  • I say "callable" because a lambda is not a function. Its a function object – 463035818_is_not_an_ai Mar 17 '21 at 16:04
  • Do you want `my_f_params` to be a structure that holds a `double` and a custom function so that you can pass them to `xrootf` and use that double and the custom function inside `xrootf` ? – 463035818_is_not_an_ai Mar 17 '21 at 16:06
  • @largest_prime_is_463035818 Yes thats what I try to do. But the function is created through the `auto` command. So I dont know if I should call it a function or what. But you got my point. ** Also** maybe check the last last part of the Question. Thats EXACTLY what I try to achieve but on Cpp (in order to be faster). – Billy Matlock Mar 17 '21 at 16:11
  • "But the function is created through the auto command" you seem to have some misconception concerning `auto`. `auto` does not mean "any type"! It means "the compiler can figure out the type and replace it for me right there". The compiler still needs a way to deduce the type, but it cannot for `auto inter_auto(double x, double y);`. Anyhow, while I was falling back to old bad habits of discussing in comment someone wrote a great answer that I think covers what you want to do. – 463035818_is_not_an_ai Mar 17 '21 at 16:15
  • @BillyMatlock in your Python script, `xroot()` is *subtracting* the result of `f(flag)` from the value of `flag`, but in your C++ code, `xrootf()` is *multiplying* the result of `inter_auto(x)` with the value of `flag`. Those are not the same algorithm. So which one do you really want? – Remy Lebeau Mar 17 '21 at 16:18
  • @RemyLebeau Doesn't really matter. I mean the "addition / substraction" is irrelevant. I just want to have a way to pass those function. If I can do multiplication i can do subtraction too. A pro dude below solved it btw. SO i need to check how it works. Ty all – Billy Matlock Mar 17 '21 at 16:20
  • 2
    @BillyMatlock that "pro dude" was me :) – Remy Lebeau Mar 17 '21 at 16:22
  • OH! TRU. Thanks again <3 Also ty @largest_prime_is_463035818 for your time. – Billy Matlock Mar 17 '21 at 16:32

1 Answers1

3

auto is just a placeholder for a compiler-deduced type, depending on the context in which auto is used.

In your example, you can't use auto as the return value of my_f_params::inter_auto(), because the compiler has no way to know what type inter_auto() actually returns, so it can't deduce the type of the auto. You would need to do this instead:

struct my_f_params { 
    double flag; 
    auto inter_auto(double x, double y) { return ...; }
};

Then the compiler can deduce the type of the auto from the return statement.

Without that inline code, you would have to be explicit about the return type, eg:

struct my_f_params { 
    double flag; 
    double inter_auto(double x, double y);
};

double my_f_params::inter_auto(double x, double y) {
    return ...;
}

But in any case, this is not what you really want. Your xrootf() function is trying to call inter_auto() with only one parameter, but my_f_params::inter_auto() is declared to take 2 parameters instead. Based on the Python script you showed, what you really want is for inter_auto to be a reference to some other external function instead. In which case, you can use std::function for that purpose (and there is no need to use std::bind() with a lambda at all).

Try this:

#include <iostream>
#include <functional>

struct my_f_params { 
    double flag; 
    std::function<double(double)> inter_auto;
};

double xrootf(double x, void * p)
{
    my_f_params * params = static_cast<my_f_params*>(p);
    return params->flag * params->inter_auto(x);
}

auto new_f(double x){
    return [x](double y) {
        return x * y;
    };
}

int main(int argc, char const *argv[])
{
    my_f_params p;
    p.flag = 123.45;
    p.inter_auto = new_f(-0.5);
    std::cout << xrootf(+2, &p) << std::endl;
    return 0;
} 

Demo

When calling xrootf(), the resulting equation will be:

flag * (x * y)

which in this example is:

123.45 * (-0.5 * +2) = -123.45

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
  • WOW. You did it! I didn't even know the existance of `std::function` Give me a moment to think about it – Billy Matlock Mar 17 '21 at 16:20
  • @BillyMatlock worth mentioning that there is no need for `void*` unless thats a requirement. I suppose it is only in this answer to be in sync with the code in your question. Using `void*` comes with some issues that are better avoided – 463035818_is_not_an_ai Mar 17 '21 at 16:22
  • @largest_prime_is_463035818 Unfortunately, void * has to be the case for the Library I plan to use on the real code (thats thw ""MWE"", its a GSL library for rootfinding) – Billy Matlock Mar 17 '21 at 16:24
  • @BillyMatlock except that you did not actually provide any MWE showing how `xrootf()` was being used with that library. But that is OK, we get the gist of what you want, no need to go any further. – Remy Lebeau Mar 17 '21 at 16:25
  • @RemyLebeau It worked on me too! Sorry it took some time, Had to add "-lstdc++" for it to be compiled. All this was due to `std::function` ? How did you know exactly it was that? Because I tried casting the lambda/auto or whatever-is-called variable as double but couldnt get it. How did you know you should do it this way? Ty again! – Billy Matlock Mar 17 '21 at 16:35
  • @BillyMatlock "*How did you know you should do it this way?*" - with experience comes wisdom. You'll get there someday, just keep practicing and learning. Get yourself some [good C++ books](https://stackoverflow.com/questions/388242/). – Remy Lebeau Mar 17 '21 at 16:39
  • Alrighty , just seemed strange to me that you knew you should convert the type to std::function<..> ! Good Job! I have been spending free time on this ( https://www.amazon.com/Introduction-Algorithms-3rd-MIT-Press/dp/0262033844 ) since I'm working on physics. But will probably change it to a Cpp book :) TY for all – Billy Matlock Mar 17 '21 at 16:44