c++ 参数 auto 详解

1,325 阅读2分钟

普通函数的参数 auto

从 C++14 开始,lambda 可以使用占位符(如 auto)来声明/定义它们的参数:

auto printCol1=[] (const auto& coll) { //generic lambda

for (const auto& elem:coll){ std::cout <<elem <<'\n'; }

}

它们允许我们传递任何类型的参数,只要lambda内部的操作是受支持的

std::vector coll{1,2,4,5};

...

printColl(coll);

// 编译矢量<int>的 lambda

printColl(std::string{"he11o"});

//编译 std::string 的 lambda

从c++ 20开始,你可以为所有函数(包括成员函数和操作符)使用占位符,比如auto。

void printColl(const auto& coll) //generic function {
or (const auto& elem : co11){

std::cout<<elem <<'\n'; }

}

此类声明只是声明/定义模板的快捷方式,如下所示:

void printColl(const T& coll)

//equivalent generic function {

for (const auto& elem: coll) { std::cout <<elem <<'\n'; }

}

唯一的区别是,通过使用auto,模板形参t就不再有名字了。因此,这个特性也被称为缩写的函数模板语法。

因为带有auto的函数是函数模板,所以所有使用函数模板的规则都适用。这尤其会导致不能在一个翻译单元(CPP文件)中实现具有自动参数的函数,而在另一个翻译单元中调用它。

带有auto参数的函数属于头文件,以便在多个CPP文件中可用(或者必须显式地实例化函数)

auto 成员函数的参数

您还可以使用此特性定义成员函数

class MyType {
...

void assign(const auto& newVal); };

该声明等价于(不同的是没有定义类型T):

class MyType {

template<typename T>

void assign(const T& newVal); };

但是,请注意,模板不能在函数内部声明。因此,有了这个特性,您就不能再在函数内部本地定义类或数据结构了

void foo() {

struct Data{

void mem(auto); //ERROR can't declare templates insides functions };

}

auto函数 与 Lambdas

具有自动形参的函数不同于lambda。例如,在不指定泛型参数的情况下,仍然不能传递带有auto作为参数的函数

bool lessByNameFunc(const auto& c1, const auto& c2) { //sorting criterion return c1.getName() < c2.getName(); //compare by name

} ...

std::sort(persons.begin(),persons.end(),

1essByNameFunc);

//ERROR:can't deduce type of parameters in sorting criterion

记住,lessByName()的声明相当于:

template<typename T1, typename T2>

bool lessByName(const T1& c1, const T1& c2) { //sorting criterion

return c1.getName()< c2.getName();

//compare by name }

因为函数模板不是直接调用的,所以编译器无法推断模板参数来编译调用。因此,必须显式地指定模板参数

std::sort(persons.begin(),persons.end(),

lessByName<Customer,Customer>); //OK

通过使用lambda,在传递lambda作为参数时不必指定模板参数的类型

lessByNameLambda = [] (const auto& c1, const auto& c2) { //sorting criterion

return c1.getName()< c2.getName();//compure by name };

std::sort(persons.begin(),persons.end(),

1essByNameLambda);

//OK

另一方面,函数模板参数很容易指定

void printFunc(const auto& arg) {
...
printFunc<std::string>("hel1o");
//剔除函数 templute 编译为 std::string
}

因为泛型lambda是一个带有泛型函数调用操作符operator()的函数对象,要显式指定模板形参,必须将其作为参数传递给operator():

auto printFunc = [] (const auto& arg) {

};
printFunc.operator()<std::string>("he11o");

//为std::string剔除lambda编译 

auto详细参数

使用auto声明函数形参的规则与使用它声明lambda形参的规则相同

  • 对于使用 auto 声明的每个参数,该函数都有一个隐式模板参数。

  • 参数可以是参数包:

    void foo(auto... args);
    

    这相当于以下内容(不引入类型)

    template<typename...Types>
    
    void foo(Types... args);
    
    
    

    不允许使用 decltype(auto)。


开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 N 天,点击查看活动详情