我不确定我是否100%理解要求的组合,但是:
#include <iostream>
#include <string>
#include <type_traits>
// if called with an rvalue (xvalue) as 2:nd arg,move or copy
std::string get_or_default(const std::string& st,std::string&& default_st) {
std::cout << "got temporary\n";
if(st.empty())
return std::move(default_st); // rval,move ctor
// return std::forward<std::string>(default_st); // alternative
else
return st; // lval,copy ctor
}
// lvalue as 2:nd argument,return the reference as-is
const std::string& get_or_default(const std::string& st,const std::string& default_st) {
std::cout << "got ref\n";
if(st.empty()) return default_st;
else return st;
}
int main() {
std::string lval = "lval";
// get ref or copy ...
decltype(auto) s1 = get_or_default("","temporary1");
decltype(auto) s2 = get_or_default("",std::string("temporary2"));
decltype(auto) s3 = get_or_default("",lval);
std::cout << std::boolalpha;
std::cout << std::is_reference_v<decltype(s1)> << "\n";
std::cout << std::is_reference_v<decltype(s2)> << "\n";
std::cout << std::is_reference_v<decltype(s3)> << "\n";
}
输出:
got temporary
got temporary
got ref
false
false
true
编辑:经过OP:s测试后,制作了一个稍微通用的版本。它可以使用lambda,例如
auto empty_check = [](const std::string& s) { return s.empty(); };
测试第一个参数是否为空。
template<typename T,typename F>
T get_or_default(const T& st,T&& default_st,F empty) {
if(empty(st)) return std::move(default_st);
// return std::forward<T>(default_st); // alternative
else return st;
}
template<typename T,typename F>
const T& get_or_default(const T& st,const T& default_st,F empty) {
if(empty(st)) return default_st;
else return st;
}
,
好吧,这里有几件事。
要直接表达您的要求,可以使用std::variant<std::string,std::string&>
之类的函数作为返回类型。虽然我还没有检查variant是否可以存储参考。
或第三方库中的等效项。要么?
您也可以编写自己的包装字符串和字符串引用的类。
(不是真实代码)
struct StringOrRef {
enum class Type {Value,Ref} type;
union {
std::string value;
std::reference_wrapper<const std::string> ref;
};
...
};
检查主题:区分C ++中的联合。
但是我认为您的示例存在更大的问题!
请考虑数据的所有权。 std :: string获取所传递数据的所有权。这就是为什么它复制数据。因此,当您的函数返回时-被调用者可以确定它具有数据,并且只要保存该值就不必担心。
如果您设计一个函数来返回对传递的参数值的引用-您需要确保在与传递的参数(返回ref的参数)寿命相同的寿命内使用该值
所以请考虑:
StringOrRef func(strging const& a,string const& b);
...
StringOrRef val;
{ // begin scope:
SomeStruct s = get_defaul();
val = func("some value",s.get_ref_to_internal_string());
}// end of val scope
val; // is in scope but may be referencing freed data.
这里的问题是临时对象SomeStruct s
。如果它的成员函数get_ref_to_internal_string() -> string&
返回对该对象的字符串字段的引用(通常是实现该对象的方式)-那么当s
超出范围时-ref无效。也就是说,它正在引用可能已提供给某些其他对象的已释放内存。
并且,如果您在val
中捕获了该引用,则val将引用无效数据。
如果全部以access violation
结尾或发出信号,您将很幸运。在最坏的情况下,您的程序会继续运行,但会随机崩溃。
本文链接:https://www.f2er.com/3148520.html