gpt4 book ai didi

c++ - 如果函数的返回值将用作右值引用而不是左值,是否有办法使函数具有不同的行为?

转载 作者:行者123 更新时间:2023-11-30 05:02:45 27 4
gpt4 key购买 nike

我有一个执行一些中等开销操作的例程,客户端可以将结果作为字符串、整数或许多其他数据类型使用。我有一个公共(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()知道它的返回值是要变成右值引用还是要变成左值,并有不同的行为每种情况?

最佳答案

您可以使用一种代理对象实现您要求的语法。

代替ResultResult::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;
}
};

// ...

};

Live demo .

不过,这种方法有其缺点。例如,如果您改为这样写:

 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/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com