为什么基元类型和用户定义类型在从函数返回为"const"时的行为不同?
Why do primitive and user-defined types act differently when returned as 'const' from a function?
#include <iostream>
using namespace std;
template<typename T>
void f(T&&) { cout << "f(T&&)" << endl; }
template<typename T>
void f(const T&&) { cout << "f(const T&&)" << endl; }
struct A {};
const A g1() { return {}; }
const int g2() { return {}; }
int main()
{
f(g1()); // outputs "f(const T&&)" as expected.
f(g2()); // outputs "f(T&&)" not as expected.
}
问题描述嵌入了代码中。我的编译器是clang 5.0
。
我只是想知道:
为什么C 在这种情况下对内置类型和自定义类型的处理方式不同?
我没有标准的报价,但是cppreference确认了我的怀疑:
不能对非阶级非阵列prvalue进行CV测试。(注意:函数调用或铸造表达式可能会导致非类CV合格类型的序言,但CV-Qualifier立即删除。(
返回的const int
只是一个普通的int
prvalue,使得非const超载比const
One更好。
当函数返回为" const"时,为什么原始和用户定义的类型的作用有所不同?
因为const
零件是从功能返回的原始类型中删除的。原因是:
在§ 5 Expressions [expr]
中的C 11中(第84页(:
8
每当glvalue表达式以操作员的操作数出现时 期望该操作数,lvalue-to-rvalue(4.1(, 阵列到点(4.2(或功能对二重奏(4.3(标准转换为 应用于将表达式转换为prvalue。[注意:因为CV-Quali-firer 当 表达被转换为prvalue,一种类型的LVALUE表达 例如,可以使用const -int在类型的prvalue表达式的情况下使用 int是必需的。 - 末尾注]
类似地来自§ 5.2.3 Explicit type conversion (functional notation) [expr.type.conv]
(第95页(:
2
表达式t((,其中t是简单型特异性或 非阵列完整对象类型或 (可能是cv-qualifif(void类型,创建了指定的 类型,即有价值的(8.5;对于 void((案例(。[注意:如果t是一种非课堂类型,则是cv qualifif的 确定结果的类型时,忽略了CV-Qualifirer Prvalue(3.10(。 - 末尾注]
这意味着const int
由g2()
返回的prvalue有效地将其视为int
。
引用标准,
§8/6表达式[expr]
如果prvalue最初具有" cv t"类型,其中t是一个 CV UNCALIFIFIED非级别的非阵列类型,表达式的类型 在进行任何进一步分析之前已将其调整为t。
和§8/9表达式[expr]
(强调我的(
每当glvalue表达式以操作符的操作数出现时 这预计该操作数,lvalue-to-rvalue, 阵列到二次或函数对置标准转换是 应用于将表达式转换为prvalue。 [注意:因为 从非类别的表达式中删除了CV-质量 当将表达式转换为prvalue时键入lvalue 例如,
const int
类型的表达可以使用prvalue的地方使用 需要int
类型的表达。 - 终点注]
so对于g2()
,int
是一种非类型类型,并且(返回值(g2()
是prvalue表达式,然后删除const
预选赛,因此返回类型不是const int
,而是int
。这就是为什么f(T&&)
被称为。
以前的答案是完全有效的。我只想添加潜在的动机,为什么有时返回const对象可能有用。在下面的示例中,class A
对class C
的内部数据进行了视图,在某些情况下不可修改该数据(免责声明,对于简短的某些基本零件被遗漏了 - 也可能有更轻松的方法来实施此行为(:
class A {
int *data;
friend class C; // allow C to call private constructor
A(int* x) : data(x) {}
static int* clone(int*) {
return 0; /* should actually clone data, with reference counting, etc */
}
public:
// copy constructor of A clones the data
A(const A& other) : data(clone(other.data)) {}
// accessor operators:
const int& operator[](int idx) const { return data[idx]; }
// allows modifying data
int& operator[](int idx) { return data[idx]; }
};
class C {
int* internal_data;
public:
C() : internal_data(new int[4]) {} // actually, requires proper implementation of destructor, copy-constructor and operator=
// Making A const prohibits callers of this method to modify internal data of C:
const A getData() const { return A(internal_data); }
// returning a non-const A allows modifying internal data:
A getData() { return A(internal_data); }
};
int main()
{
C c1;
const C c2;
c1.getData()[0] = 1; // ok, modifies value in c1
int x = c2.getData()[0]; // ok, reads value from c2
// c2.getData()[0] = 2; // fails, tries to modify data from c2
A a = c2.getData(); // ok, calls copy constructor of A
a[0] = 2; // ok, works on a copy of c2's data
}
- 递归模板化函数不能分配给具有常量限定类型"const tt &"的变量"state"
- 视觉工作室 2017;启用 /permissive 时,类型 "const wchar_t *" 的参数与类型 "PWSTR" 的参数不兼容
- 无法使用类型 'const char *' 的左值初始化类型 'char *' 的成员子对象
- "const wchar_t *" 类型的值不能用于初始化类型 "const PWSTR" 的实体
- 错误:对类型 'const ItemInstance' 的引用无法绑定到类型 'void' 的右值
- C++ 类型 "char" 的参数与类型 "const char" 的参数不兼容
- 在这种情况下,如何从类型 "const char*" 初始化字段?
- 类型"const char[2]"的值不能隐式转换为"int"错误C++
- 错误:数组下标的类型"const bool[int]"无效
- 错误:C2679 二进制"==":未找到采用类型 'const std::string' 的右侧操作数的运算符(或者没有可接受的转换)
- 类型 "const char *" 的参数与类型 "char *" 的参数不兼容
- 错误:"->"的基本操作数具有非指针类型"const"
- 作为返回类型"const int&"做什么?
- 类型 "const char*" 的参数与类型 "char*" 的参数不兼容。但是为什么?:(
- 类型 "const char*" 的参数与类型 "Person" 的参数不兼容
- C++:"错误:类型'const char*'和'const char [28]'的操作数无效到二进制'ope
- 类型 "const char *" 的参数与类型 "LPCWSTR" 的参数不兼容
- 错误:从不兼容的类型 'const char *' 分配给'char'
- 类型 "const char *" 的默认参数与类型 "char *" 的参数不兼容
- 类型 "const char *" 的参数与 "LPSTR" C++ 类型的参数不兼容