c++ - std::reference_wrapper 和 T 之间的最佳可行重

最近,我决定编写一个类来存储带有 reference_wrapper 和 vector 的变体,以便选择拥有该值或仅拥有它的引用。即 std::variant<vector<string>, reference_wrapper<const vector<string>>> .

有趣的部分是变体根据初始化存储的内容。 我做了一个小investigation ,事实证明,在所有情况下 vector<string>类型获胜,除了通过 std::cref 传递的情况。这同样适用于函数(有点意料之中,因为构造函数在这方面类似于函数)

void f(vector<string>); // #1
void f(reference_wrapper<const vector<string>>); // #2

vector<string> data;
const vector<string>& get_data();

f(data); // #1
f(std::cref(data)) // #2

f(get_data()); // #1
f(std::cref(get_data())) // #2

问题是为什么 vector<string>在这里有优先权。我查看了最佳可行函数部分here ,但这没有多大意义。看来,那

4) or, if not that, F1 is a non-template function while F2 is a template specialization

部分选择vector<string>reference_wrapper<vector<string>> (因为 reference_wrapper 构造函数是模板化的),但我不确定,因为使用规则我不能完全理解它们是否相等

1) There is at least one argument of F1 whose implicit conversion is better than the corresponding implicit conversion for that argument of F2

有人可以描述在每种情况下应用的所有隐式转换并说明一个重载优于另一个重载的真正原因吗?对我来说,它们如下:

f(data) = f(vector<string>&) -> (*exact match* implicit conversion) -> f(vector<string>)

f(data) = f(vector<string>&) -> (*conversion* implicit conversion) -> f(reference_wrapper<vector<string>>)

我错过了什么吗?

与此主题相关的另一个问题:Ranking of implicit conversion sequences section again,here留个问题,是T(const T&)被认为是完全匹配(用户定义的类类型到同一类的转换)还是转换

最佳答案

首先,虽然std::reference_wrapper是标准库的一部分,它被视为用户定义的类型。

例如 std::vector & 的隐式转换至 const std::vector &总是优先于 std::vector& 的隐式转换至 std::reference_wrapper<vector> .那是因为(按照标准)前者是标准转换,而后者是用户定义的转换。第一个称为标准转换,因为它添加了一个 const到你的类型,但第二个被视为将某种类型转换为完全不同的类型。

检查 this code并查看 cppreference.com .

其次,我正在尝试猜测一些好的替代方案。我看到您想要存储对 vector 的引用或移动/(尽可能便宜地复制)或(您可以说直接初始化)类中的数据,如果它尚未存储(安全地)在一些变量中。也许您可以考虑使用移动语义。你可以玩代码 here

using TVar = std::variant<reference_wrapper<const vector<string>>, vector<string>>;

class Config {
private:
    TVar data;
public:
    const vector<string>& get_data() const{
        if (data.index() == 1)
            return get<1>(data);
        else return get<0>(data);
    }
    Config(const vector<string>& it):data(cref(it)){}
    Config(vector<string>&& it):data(move(it)){}
};

这里我们有两个函数。

  1. 引用“存储值”(更准确地说是左值)的一个。将它包装在 cref 中,以便它导致 reference_wrapper变体中的替代方案是最佳重载。
  2. 另一个施展魔法。它是对直接写入的值(又名 pvalues)和使用魔法 std::move 的值的引用函数(又名 xvalues)。如果你从未见过这个,请引用这个令人尊敬的问答What is move semantics?

catch(...) :),就是这样。另请注意,您不需要 std::monostate因为这只需要使变体默认可构造(不带参数)。您可以像这样使您的类默认可构造。

    Config(vector<string>&& it = {}):data(move(it)){}

关于c++ - std::reference_wrapper<const T> 和 T 之间的最佳可行重载函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/68876690/

相关文章:

python - 自动将 Jupyter notebook 的副本维护为纯 Python 代码

ios - flutter app 不是由 flutter build ios 运行,而是由 xco

javascript - JS CSS HTML - 创建一个独立于文本数量而保持相同宽度的按钮

android - 何时使用内部应用共享与内部测试 (google play)?

python - 在 Python 中序列化/反序列化类对象的最佳方法是什么?

javascript - 在开始下一个功能之前等待一个功能完成

reactjs - 访问 XMLHttpRequest 被 CORS 阻止,请求的资源上不存在 'A

css - 有什么方法可以从 CSS 使用 SVG Sprite 吗?

linux - 安排每日 Docker 容器重启/重置

react-native - # 无法被克隆