首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 开发语言 > C++ >

新的auto关键字不能获得"引用"的类型啊为什么

2013-12-26 
新的auto关键字不能取得引用的类型啊,为什么?我有下面一小段代码,我想用auto关键字返回一个引用,然后改

新的auto关键字不能取得"引用"的类型啊,为什么?
我有下面一小段代码,我想用auto关键字返回一个引用,然后改变这个引用的值。我发现不成功。

                              

是你的理解产生了问题,来源于你对declaration没有形成一个正确的观念。对于如下声明:

int & a = ...;

你是“很自然”地把上述语句分成如下两部分:int&和a,所以对于auto i=obj.Get();才会产生auto应该是int&的误解。实际上declaration是如下这样划分的(为叙述方便,偶简化了一些无关痛痒的细节):

对于声明T D,D称为declarator,对于一个普通声明来说,D就是identifier,但对于指针、引用等declarator来说,D不是identifier,D是由指针声明符或引用声明符与identifier一起组合而成的,此时identifier称为declarator-id,例如对于T & D1 来说,D1是declarator-id,&是引用声明符,&D1是declarator,T是被引用的类型,D1这个declarator-id的type(不是指像int、float这种类型修饰符)是引用,T & D1分为两部分,分别为T和&D1,而非T&和D1。

接下来auto是如何推导的呢?它首先定出declarator-id的类型,这个过程不是推导的,而是根据声明的抽象表示形式决定的,如果是&D1这种形式,那么这个declarator-id的类型就是引用,如果是*D1这种形式,就是指针,决定了declarator-id的类型后,再根据模板实参推演的规则推导auto的实际类型,所以,对于auto i=obj.Get();来说,是不会把i推导为引用类型的,只有当auto &i=obj.Get();时,才属于引用类型。

标准的条款:

7.1.6.4 auto specifier

..........
6 Once the type of a declarator-id has been determined according to 8.3, the type of the declared variable using the declarator-id is determined from the type of its initializer using the rules for template argument deduction. Let T be the type that has been determined for a variable identifier d. Obtain P from T by replacing the occurrences of auto with either a new invented type template parameter U or, if the initializer is a braced-init-list (8.5.4), with std::initializer_list<U>. The type deduced for the variable d is then the deduced A determined using the rules of template argument deduction from a function call (14.8.2.1), where P is a function template parameter type and the initializer for d is the corresponding argument. If


the deduction fails, the declaration is ill-formed.
[解决办法]
要引用的话,目前只能用 decltype 了。
[解决办法]



是你的理解产生了问题,来源于你对declaration没有形成一个正确的观念。对于如下声明:

int & a = ...;

你是“很自然”地把上述语句分成如下两部分:int&和a,所以对于auto i=obj.Get();才会产生auto应该是int&的误解。实际上declaration是如下这样划分的(为叙述方便,偶简化了一些无关痛痒的细节):

对于声明T D,D称为declarator,对于一个普通声明来说,D就是identifier,但对于指针、引用等declarator来说,D不是identifier,D是由指针声明符或引用声明符与identifier一起组合而成的,此时identifier称为declarator-id,例如对于T & D1 来说,D1是declarator-id,&是引用声明符,&D1是declarator,T是被引用的类型,D1这个declarator-id的type(不是指像int、float这种类型修饰符)是引用,T & D1分为两部分,分别为T和&D1,而非T&和D1。

接下来auto是如何推导的呢?它首先定出declarator-id的类型,这个过程不是推导的,而是根据声明的抽象表示形式决定的,如果是&D1这种形式,那么这个declarator-id的类型就是引用,如果是*D1这种形式,就是指针,决定了declarator-id的类型后,再根据模板实参推演的规则推导auto的实际类型,所以,对于auto i=obj.Get();来说,是不会把i推导为引用类型的,只有当auto &i=obj.Get();时,才属于引用类型。

标准的条款:

7.1.6.4 auto specifier

..........
6 Once the type of a declarator-id has been determined according to 8.3, the type of the declared variable using the declarator-id is determined from the type of its initializer using the rules for template argument deduction. Let T be the type that has been determined for a variable identifier d. Obtain P from T by replacing the occurrences of auto with either a new invented type template parameter U or, if the initializer is a braced-init-list (8.5.4), with std::initializer_list<U>. The type deduced for the variable d is then the deduced A determined using the rules of template argument deduction from a function call (14.8.2.1), where P is a function template parameter type and the initializer for d is the corresponding argument. If
the deduction fails, the declaration is ill-formed.

你的回答非常专业!但是仍然有个问题,如果我把Get函数改成

int* GetP(){return &m_i;}

然后main函数里面如果

auto p=obj.GetP();

那么这个auto就能自动推导出p是一个指针了。你不是说"D是由指针声明符或引用声明符与identifier一起组合而成的"吗? 看起来指针的处理和引用的处理还不太一样啊。

还请继续解释,谢谢!
所以说,看模板推导规则了。
WG21/N3797
7.1.6.4
4 The type of a variable declared using auto or decltype(auto) is deduced from its initializer. This use is allowed when declaring variables in a block (6.3), in namespace scope (3.3.6), and in a for-init-statement (6.5.3).
auto or decltype(auto) shall appear as one of the decl-specifier s in the decl-specifier-seq and the declspecifier-seq shall be followed by one or more init-declarator s, each of which shall have a non-empty initializer . In an initializer of the form
( expression-list )
the expression-list shall be a single assignment-expression .
[ Example:
auto x = 5; // OK: x has type int
const auto *v = &x, u = 6; // OK: v has type const int*, u has type const int
static auto y = 0.0; // OK: y has type double
auto int r; // error: auto is not a storage-class-specifier
auto f() -> int; // OK: f returns int


auto g() { return 0.0; } // OK: g returns double
auto h(); // OK: h’s return type will be deduced when it is defined
—end example ]
7 When a variable declared using a placeholder type is initialized, or a return statement occurs in a function
declared with a return type that contains a placeholder type, the deduced return type or variable type
is determined from the type of its initializer. In the case of a return with no operand, the initializer is
considered to be void(). Let T be the declared type of the variable or return type of the function. If the
placeholder is the auto type-specifier , the deduced type is determined using the rules for template argument
deduction. If the deduction is for a return statement and the initializer is a braced-init-list (8.5.4), the
program is ill-formed. Otherwise, obtain P from T by replacing the occurrences of auto with either a
new invented type template parameter U or, if the initializer is a braced-init-list , with std::initializer_-list<U>. Deduce a value for U using the rules of template argument deduction from a function call (14.8.2.1),
where P is a function template parameter type and the initializer is the corresponding argument.
 If the
deduction fails, the declaration is ill-formed. Otherwise, the type deduced for the variable or return type is
obtained by substituting the deduced U into P. [ Example:
auto x1 = { 1, 2 }; // decltype(x1) is std::initializer_list<int>
auto x2 = { 1, 2.0 }; // error: cannot deduce element type
—end example ]
[ Example:
const auto &i = expr;
The type of i is the deduced type of the parameter u in the call f(expr) of the following invented
function template:
template <class U> void f(const U& u);
—end example ]
If the placeholder is the decltype(auto) type-specifier , the declared type of the variable or return type
of the function shall be the placeholder alone. The type deduced for the variable or return type is determined
as described in 7.1.6.2, as though the initializer had been the operand of the decltype. [ Example:
int i;
int&& f();
auto x3a = i; // decltype(x3a) is int
decltype(auto) x3d = i; // decltype(x3d) is int
auto x4a = (i); // decltype(x4a) is int
decltype(auto) x4d = (i); // decltype(x4d) is int&
auto x5a = f(); // decltype(x5a) is int
decltype(auto) x5d = f(); // decltype(x5d) is int&&
auto x6a = { 1, 2 }; // decltype(x6a) is std::initializer_list<int>
decltype(auto) x6d = { 1, 2 }; // error, { 1, 2 } is not an expression
auto *x7a = &i; // decltype(x7a) is int*
decltype(auto)*x7d = &i; // error, declared type is not plain decltype(auto)
—end example ]
14.8.2.1 Deducing template arguments from a function call [temp.deduct.call]
1
Template argument deduction is done by comparing each function template parameter type (call it P) with
the type of the corresponding argument of the call (call it A) as described below. If removing references
and cv-qualifiers from P gives std::initializer_list<P
0
> for some P
0
and the argument is an initializer
list (8.5.4), then deduction is performed instead for each element of the initializer list, taking P
0
as a function
template parameter type and the initializer element as its argument. Otherwise, an initializer list argument
causes the parameter to be considered a non-deduced context (14.8.2.5). [ Example:


template<class T> void f(std::initializer_list<T>);
f({1,2,3}); // T deduced to int
f({1,"asdf"}); // error: T deduced to both int and const char*
template<class T> void g(T);
g({1,2,3}); // error: no argument deduced for T
—end example ] For a function parameter pack that occurs at the end of the parameter-declaration-list ,
the type A of each remaining argument of the call is compared with the type P of the declarator-id of the
function parameter pack. Each comparison deduces template arguments for subsequent positions in the
template parameter packs expanded by the function parameter pack. When a function parameter pack
appears in a non-deduced context (14.8.2.5), the type of that parameter pack is never deduced. [ Example:
template<class ... Types> void f(Types& ...);
template<class T1, class ... Types> void g(T1, Types ...);
template<class T1, class ... Types> void g1(Types ..., T1);
void h(int x, float& y) {
const int z = x;
f(x, y, z); // Types is deduced to int, float, const int
g(x, y, z); // T1 is deduced to int; Types is deduced to float, int
g1(x, y, z); // error: Types is not deduced
g1<int, int, int>(x, y, z); // OK, no deduction occurs
}
—end example ]
2
If P is not a reference type:
— If A is an array type, the pointer type produced by the array-to-pointer standard conversion (4.2) is
used in place of A for type deduction; otherwise,
— If A is a function type, the pointer type produced by the function-to-pointer standard conversion (4.3)
is used in place of A for type deduction; otherwise,
— If A is a cv-qualified type, the top level cv-qualifiers of A’s type are ignored for type deduction.
以下超过字符限制略。

热点排行