#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.
}
Run Code Online (Sandbox Code Playgroud)
问题描述嵌入在代码中.我的编译器是clang 5.0.
我只是好奇:
在这种情况下,为什么C++会以不同方式处理内置类型和自定义类型?
最近我读过,从函数返回值来为非内置类型限定返回类型const是有意义的,例如:
const Result operation() {
//..do something..
return Result(..);
}
Run Code Online (Sandbox Code Playgroud)
我很难理解这个的好处,一旦对象被返回肯定是调用者的选择来决定返回的对象是否应该是const?
我刚刚发现了最令人困惑的错误,我不明白为什么编译器没有为我标记它.如果我写下面的内容:
string s = "abcdefghijkl";
cout << s << endl;
s.substr(2,3) = "foo";
s.substr(8,1) = '.';
s.substr(9,1) = 4;
cout << s << endl;
Run Code Online (Sandbox Code Playgroud)
编译器对此没有任何问题,并且赋值语句似乎根据打印出的内容没有任何效果.相反,
s.front() = 'x';
Run Code Online (Sandbox Code Playgroud)
具有我期望的效果(因为front返回对字符的引用)改变底层字符串,和
s.length() = 4;
Run Code Online (Sandbox Code Playgroud)
也有产生编译器错误的预期效果,抱怨你不能分配给不是左值的东西,因为length返回一个整数.(好吧,size_t无论如何.)
那么......为什么编译器不会抱怨分配给substr调用的结果呢?它返回一个字符串值,而不是引用,所以它不应该是可赋值的,对吧?但我在g++(6.2.1)和clang++(3.9.0)中尝试了这个,所以它似乎不是一个bug,它似乎也不敏感C++版本(试过03,11,14) ).
字符串类的接口通常具有名为IsEmpty(VCL)或empty(STL)的方法.这是绝对合理的,因为它是一个特殊情况,但使用这些方法的代码通常必须否定这个谓词,这导致"光学(甚至心理)开销"(感叹号不是很明显,特别是在一个左括号后) ).例如,请参阅此(简化)代码:
/// format an optional time specification for output
std::string fmtTime(const std::string& start, const std::string& end)
{
std::string time;
if (!start.empty() || !end.empty()) {
if (!start.empty() && !end.empty()) {
time = "from "+start+" to "+end;
} else {
if (end.empty()) {
time = "since "+start;
} else {
time = "until "+end;
}
}
}
return time;
}
Run Code Online (Sandbox Code Playgroud)
它有四个否定,因为空案例是要跳过的.在设计界面时,我经常会观察到这种否定,这不是一个大问题,但它很烦人.我只想支持编写易于理解且易于阅读的代码.我希望你能理解我的观点.
也许我只是失明了:你如何解决上述问题?
编辑:在阅读了一些评论后,我认为原始代码使用System::AnsiString …
///////////////////////////////////////
class A {
...
const double funA(void)
{...}
};
A a;
double x = a.funA();
// although the intention is to
// enforce the return value to be const and cannot be
// modified, it has little effect in the real world.
class A2 {
...
double funB(void)
{...}
};
///////////////////////////////////////
class A {
void setA(const double d)
{ // now you cannot change the value of d, so what?
// From my point of view, it is NOT …Run Code Online (Sandbox Code Playgroud) 考虑这个功能
const std::string f()
{
return "hello";
}
Run Code Online (Sandbox Code Playgroud)
和电话
std::string x = f();
Run Code Online (Sandbox Code Playgroud)
无论值返回类型是否为const,返回值是否为const,都会阻止编译器执行返回值优化?
我对RVO的理解是返回的对象直接构造在函数外部的变量中.但是,如果返回类型是const T,这与a不同T,那么RVO会被阻止吗?
我正在开发一个由不同模块组合而成的大型项目.我们有exporter一个模板功能export<T>(const T& obj),其工作只是在POD类型(它static_assert的is_pod,如果你很好奇).目前我坐在系统的一部分,负责编目由元数据描述的一些实体(它们的类型无关紧要).元数据本身由一些被调用的函数返回metadata describe(const entity& obj),并且在返回后应该是不可变的.当然,函数本身将metadata成员设置在其体内.
由于上面提到的事实,我需要设计一个const POD类型.由于POD类型不能具有用户定义的构造函数,因此成员变量本身不能const.const直接从值返回变量describe 是没有意义的(或者至少可以说没有帮助).
所以基本上我到目前为止所想到的是:
exporter.export<T>(...)的metadata,但因为它只能解决当前类的问题,这不是一个真正的解决方案,同时在最终产品中会出现许多类型的实体(我不是在谈论.重载函数用于所有类型的似乎只是错误.immutable包装并从中返回describe.这就是我目前正在做的事情,因为我无法找到解决问题的更好方法.包装器提供隐式转换const &T并存储T自身内部,因此可以直接传递给export函数.有没有更好的方法从函数返回不可变的POD类?我错过了什么吗?为简单起见,假设假设metadata定义如下:
struct metadata{
int parameter1;
time_t parameter2;
};
Run Code Online (Sandbox Code Playgroud)
并按describe如下方式工作(目前,跳过当前的解决方案):
metadata describe(const entity& obj){
metadata …Run Code Online (Sandbox Code Playgroud) 以下代码编译良好g++ (GCC) 4.7.1 20120721,但最近构建失败clang version 3.2 (trunk).
struct Y {};
struct X {
operator const Y() const { return Y(); }
};
void f(Y&& y) {}
int main()
{
f(X());
return 0;
}
Run Code Online (Sandbox Code Playgroud)
将转换运算符更改operator Y() const为足以使代码在两个编译器上进行编译.
在这种情况下,哪个编译器实际上符合标准?标准实际上对此有何看法?
请求的逐字错误:
bla.cpp:14:5: error: no viable conversion from 'X' to 'Y'
f(X());
^~~
bla.cpp:1:8: note: candidate constructor (the implicit copy constructor) not viable: no known conversion from 'X' to
'const Y &' for 1st argument
struct Y { …Run Code Online (Sandbox Code Playgroud) 对于像int这样的基本数据类型,代码片段会出现编译错误
i++ = 2;
Run Code Online (Sandbox Code Playgroud)
所以显然i++不是左值
但是当用c ++重载自定义类时,大多数人都认为post增量运算符的签名应该是这样的
Date Date::operator++(int) {
Date temp = *this;
// do increment
return temp;
}
Run Code Online (Sandbox Code Playgroud)
我的问题是为什么不应该返回类型const Date而不是Date原始类型.
我正在编写一本关于运算符重载的示例教科书,它让我想知道返回"常量值"(例如operator+).据我了解,如果我作为a返回任何内容const,则以后无法修改.说我有这个粗略的例子:
#include <iostream>
using namespace std;
class Temp {
private:
int val;
public:
Temp(){};
Temp(int v):val(v){};
const Temp operator+(const Temp& rhs) const {
return Temp(this->val + rhs.val);
}
int getVal() { return this->val; }
void setVal(int v) { this->val = v; }
};
int main() {
Temp t1, t2, t3;
t1 = Temp(4);
t2 = Temp(5);
t3 = t1 + t2;
cout << t3.getVal() << endl;
t3.setVal(100);
cout << t3.getVal() << endl;
}
Run Code Online (Sandbox Code Playgroud)
之后t3 = …
c++ ×10
c++11 ×3
string ×2
api ×1
clang ×1
coding-style ×1
g++ ×1
immutability ×1
lvalue ×1
overloading ×1
readability ×1
rvo ×1
standards ×1
substring ×1