How to Pass Auto as an Argument in C++

Is there a way to pass auto as an argument in C++?


C++20 allows auto as function parameter type

This code is valid using C++20:

int function(auto data) {
// do something, there is no constraint on data
}

As an abbreviated function template.

This is a special case of a non constraining type-constraint (i.e. unconstrained auto parameter).
Using concepts, the constraining type-constraint version (i.e. constrained auto parameter) would be for example:

void function(const Sortable auto& data) {
// do something that requires data to be Sortable
// assuming there is a concept named Sortable
}

The wording in the spec, with the help of my friend Yehezkel Bernat:

9.2.8.5 Placeholder type specifiers [dcl.spec.auto]

placeholder-type-specifier:

type-constraintopt auto


type-constraintopt decltype ( auto )


  1. A placeholder-type-specifier designates a
    placeholder type that will be replaced later by deduction from an
    initializer.

  2. A placeholder-type-specifier of the form
    type-constraintopt auto can be used in the decl-specifier-seq of a
    parameter-declaration of a function declaration or lambda-expression
    and signifies that the function is an abbreviated function template
    (9.3.3.5) ...

How to use auto keyword in argument list in C++ 11?


void get_index(auto s_arra[], auto elem) {
//...
}

Would be valid only in C++20 (gcc error message is misleading)

previously, you use template the verbose way

template <typename T1, typename T2>
void get_index(T1 s_arra[], T2 elem) {
//...
}

and probably they use same type, so

template <typename T>
void get_index(T s_arra[], T elem) {
//...
}

How to pass an Auto variable as input to another function

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

auto parameter type in functions

Ok, so thanks to Piotr pointing this other question asking about the same thing, I found the information in a comment that will resolve this, here it is:

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4040.pdf

page 16, chapter 5.1.1 named generic functions

A generic function is a function template whose
template-parameter-list has a parameterdeclaration whose
type-specifier is either auto or a constrained-type-name.

[ Example:

auto f(auto x); // Ok
void sort(C& c); // Ok (assuming C names a concept)

— end example ]

This seems rather positive :)

followed by the excpected obvious wording, that matches generic lambda:

The declaration of a generic function has a template-parameter-list
that consists of one invented type template-parameter for each
occurrence of auto.

[ Example: The following generic function declarations are equivalent:

template<typenaem T>  
conxtexpr bool C() { ... }
auto f(auto x, const C& y);
template<typename T1, C T2>
auto f(T1 x, const T2& y);

The type of y is a type parameter constrained by C. — end example ]

Why auto is not allowed as function argument?

This syntax was proposed in the Concepts TS, which did not make it into C++17 for various reasons.

Despite some critique I've outlined below, it has been added in C++20.


Note: the following part of the answer has been made obsolete by merging P1141R2 into the standard. I'll leave it here for reference.

However, even if we finally get Concepts in the next iteration (probably C++20), it is not clear the desired syntax will make it into the standard. In this paper, Richard Smith and James Dennett critique the so called "Terse template notations", saying

The Concepts TS introduces too many syntaxes for a function template declaration. Some of those syntaxes have no clear, consistent syntactic marker for templates, which is important semantic information for the reader of the code (remembering that code is read vastly more than it is written).

They go on to propose a different syntax to achieve the goal, while keeping template declarations more consistent:

=> Require an explicit sigil to declare a function to be a template

Replace

void f(auto a) {}
template<typename T> void g(auto a) {}

with

template<...> void f(auto a) {}
template<typename T, ...> void g(auto a) {}

The ​...​ sigil in the ​template-parameter-list indicates that
additional template parameters will be inferred from the declaration.

So Tl;dr: There are a bunch of reasons related to the standardization procedure why we don't have it in C++17, and there are more reasons why we probably won't ever get it. If I understood the paper correctly, the key point being that every template should be introduced with a template keyword.

Passing auto as a parameter (for pointer to object)

This is the perfect case for a template, I don't understand why you are trying to avoid it:

template < typename T >
inline __device__ T* checkPointer(T* pointer, const char *file, int line)
{
if (pointer == nullptr)
{
// do error logging
}

return pointer;
}

This is very clear and clean and you can use it as if there was an auto there:

int main(int argc, char** argv)
{
SomeObject* myObj = checkAlloc(new SomeObject());
}

As you can see, there are automatic argument deduction capabilities that don't even require any type specification...

Oh, and notice that I changed char * file to const char * file as C++11 doesn't allow conversion of literals to char *

auto as function argument

It wasn't added because it's another thing to add and time is not infinite. We cannot expect all useful enhancements to be added in one go, can we? As you have identified, it will be in C++17.



Related Topics



Leave a reply



Submit