- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我有一个执行一些中等开销操作的例程,客户端可以将结果作为字符串、整数或许多其他数据类型使用。我有一个公共(public)数据类型,它是内部数据类型的包装器。我的公开课看起来像这样:
class Result {
public:
static Result compute(/* args */) {
Result result;
result.fData = new ExpensiveInternalObject(/* args */);
return result;
}
// ... constructors, destructor, assignment operators ...
std::string toString() const { return fData->toString(); }
int32_t toInteger() const { return fData->toInteger(); }
double toDouble() const { return fData->toDouble(); }
private:
ExpensiveInternalObject* fData;
}
如果你想要字符串,你可以这样使用它:
// Example A
std::string resultString = Result::compute(/*...*/).toString();
如果你想要不止一种返回类型,你可以这样做:
// Example B
Result result = Result::compute(/*...*/);
std::string resultString = result.toString();
int32_t resultInteger = result.toInteger();
一切正常。
但是,我想修改此类,以便在用户只需要一种结果类型时无需在堆上分配内存。例如,我希望示例 A 本质上相当于,
auto result = ExpensiveInternalObject(/* args */);
std::string resultString = result.toString();
我考虑过构建代码,以便将 args 保存到 Result
的实例中,使 ExpensiveInternalObject
直到终端函数(toString
/toInteger
/toDouble
),并使用右值引用限定符重载终端函数,如下所示:
class Result {
// ...
std::string toString() const & {
if (fData == nullptr) {
const_cast<Result*>(this)->fData = new ExpensiveInternalObject(/*...*/);
}
return fData->toString();
}
std::string toString() && {
auto result = ExpensiveInternalObject(/*...*/);
return result.toString();
}
// ...
}
虽然这避免了示例 A 调用站点的堆分配,但这种方法的问题是您必须开始考虑线程安全问题。您可能希望将 fData
设为 std::atomic
,这会增加示例 B 调用站点的开销。
另一种选择是制作两个版本的 compute()
以不同的名称,一个用于 Example A 用例,一个用于 Example B 用例,但这对API 的用户,因为现在他们必须研究使用哪个版本的方法,如果选择错误的版本,他们的性能会很差。
我不能使 ExpensiveInternalObject
成为 Result
中的值字段(与指针相反),因为这样做需要在公共(public)头文件中公开太多内部结构。
有没有办法让第一个函数compute()
知道它的返回值是要变成右值引用还是要变成左值,并有不同的行为每种情况?
最佳答案
您可以使用一种代理对象实现您要求的语法。
代替Result
,Result::compute
可以返回一个代表Result
promise 的对象。这个 Promise
对象可以有一个转换运算符,它隐式转换为一个 Result
,这样“示例 B”仍然像以前一样工作。但是 promise 也可以有它自己的 toString()
, toInteger()
, ...“Example A”的成员函数:
class Result {
public:
class Promise {
private:
// args
public:
std::string toString() const {
auto result = ExpensiveInternalObject(/* args */);
return result.toString();
}
operator Result() {
Result result;
result.fData = new ExpensiveInternalObject(/* args */);
return result;
}
};
// ...
};
不过,这种方法有其缺点。例如,如果您改为这样写:
auto result = Result::compute(/*...*/);
std::string resultString = result.toString();
int32_t resultInteger = result.toInteger();
result
现在不是 Result
类型,而是一个 Result::Promise
并且您最终会计算 ExpensiveInternalObject
两次!你至少可以做到fail to compile通过向 toString()
、toInteger()
... Result::Promise
的成员函数添加右值引用限定符,但它是不理想。
关于c++ - 如果函数的返回值将用作右值引用而不是左值,是否有办法使函数具有不同的行为?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49703840/
我是 C++ 的新手,正在尝试编写如下接口(interface): template class Comparable { protected: Comparable(){};
什么是左值? 最佳答案 左值是可以分配给以下值的值: lvalue = rvalue; 它是“left value”或“lefthand value”的缩写,它基本上只是=符号左侧的值,即您为其分配值
这个问题已经有答案了: Why do C and C++ support memberwise assignment of arrays within structs, but not general
C++03 $14.1/6 - "A non-type non-reference template-parameter is not an lvalue." C++0x $14.2/6- "A no
这只是出于好奇我问... 我在任何地方看到的 99% 的代码,当使用“IF”时,将采用“If (RValue == LValue) ...”格式。例子: If (variableABC == "Hel
在 C++03 中,表达式可以是右值,也可以是左值。 在 C++11 中,表达式可以是: 右值 左值 x值 gl值 右值 两个类别变成了五个类别。 这些新的表达类别是什么? 这些新类别与现有的右值和左
我正在尝试将 div 向左移动指定数量的像素,我正在使用从此处获得的 slider : http://carpe.ambiprospect.com/slider/archive/v1.3/ 所以从示例
所以我有一个函数需要将 std::vector 作为参数。我想知道声明参数的最佳方式,这样底层数组就不会被深度复制,因为它可能相当大。 // which should I choose? void m
在 C++03 中,表达式要么是右值,要么是左值。 在 C++11 中,表达式可以是: 右值 左值 xvalue glvalue 右值 两类变成了五类。 这些新的表达类别是什么? 这些新类别与现有的右
我正在尝试实现类似 find 的方法来从容器中提取对值的引用,如果找不到该值或该值的类型不兼容,则返回一个默认值。 template const T& get (key_type k, const T
我有以下代码: #include using namespace std; void test(int& a) { cout << "lvalue." << endl; } void tes
我的搜索发现许多关于右值绑定(bind)到左值的帖子,但没有任何类似的帖子。对不起,如果它是重复的。 struct StrHolder { StrHolder(std::string&& s)
这是一个后续问题 C++0x rvalue references and temporaries 在上一个问题中,我问过这段代码应该如何工作: void f(const std::string &);
为什么这不起作用: ostream& operator' lvalue to 'std::basic_ostream&&'| error: initializing argument 1 of '
偶尔,我被问到一个技巧问题:x++ 和 ++x 哪个不能在 c 中留值?很多人告诉我++x不能,因为++x的汇编代码不返回寄存器。我对此表示怀疑。所以我做了一些实验。 C 代码: #include
所以这个问题与我为实际问题选择的解决方案有关,为了尽可能提供完整的图片,这个问题是这样的:基本上我有一个带有很多模板参数的函数,我正在尝试暴露给 Python。与用宏做一些噩梦般的事情来消除我需要的所
指针很简单。有一些内存保存着一个地址。要获得(有意义的)值,取消引用返回地址指向的内存中包含的值。 引用以某种方式做一些类似的事情:它们持有指向一个临时对象的“链接”。但是当我分配或使用引用时会发生什
下面是一些示例代码: #include class Foo { public: explicit Foo(int x) : data(x) {}; Foo& operator++() {
背景 以下代码块出现在 Scott Meyers 的名著 "Effective C++" 中第 3 项: class TextBlock { public: ... const cha
我是一名优秀的程序员,十分优秀!