我厌倦了按值传递所有对象,然后移动或重载左值和右值。我正在尝试编写一个类,如果将右值传递到构造函数中,则该类可以存储左值引用或普通对象。
这是骨架:
template<typename T>
class ref {
private:
T* m_ptr = nullptr;
std::optional<T> m_obj;
bool is_lvalue = true;
public:
ref(T& lvalue_ref) : m_ptr{ &lvalue_ref } {}
ref(T&& rvalue_ref) : m_obj{ std::move(rvalue_ref) }, is_lvalue{ false } {}
T& get() {
return (is_lvalue) ? *m_ptr : *m_obj;
}
};
我想将此类与
void foo(ref<bar> r) {}
等函数一起使用,因此任何采用 ref<T>
的函数都不会进行任何复制。不幸的是,每当你获取值时,你都必须检查是否存储了引用/对象,并且 std::optional
默认构造了它的对象,即使我们存储的是左值,我们也要为此付费。是否可以创建一个存储左值引用或对象的类,并且仍然能够有一个函数采用 ref<T>
能够将 T 的左值和右值绑定到它?
我会先引用我的评论,以便大家可以全面了解我的...观点。
我同意@JaMiT,这是一个XY问题。事实上,这个问题的特点是一个没有明确定义的问题的可能解决方案的框架:你写“我厌倦了按值传递所有对象,然后移动或重载左值和右值”。如何?展示一个代码示例,让您认为您需要解决问题。您在右值引用和左值引用通用上下文上重载的上下文是吗?或者您指的是具有具体值的函数? Q 中没有解释这些方面。
但我仍然认为可以尝试一些猜测。
来自
我厌倦了按值传递所有对象,然后移动或重载左值和右值。
因为你有很多这样的代码示例(
int
可以是任何其他
具体类型),我猜?
// foo.hpp
#pragma once
void foo(int const&);
void foo(int&&);
// foo.cpp
#include <iostream>
void foo(int&) {
std::cout << "I'm for Lvalues" << std::endl;
}
void foo(int&&) {
std::cout << "I'm for Rvalues" << std::endl;
}
// main.cpp#
include "foo.hpp"
int main()
{
foo(3);
int x{3};
foo(x);
}
如果是这种情况,一种解决方案可能是仅对函数进行模板化并在 cpp 文件中实现它们,
以及您需要的两个显式实例化:
// foo.hpp
#pragma once
template<typename T>
void foo(T&&);
// foo.cpp
template<typename T>
void foo(T&&) {
if constexpr (std::is_lvalue_reference_v<T&&>) {
std::cout << "I'm for Lvalues" << std::endl;
} else {
std::cout << "I'm for Rvalues" << std::endl;
}
}
template void foo(int&);
template void foo(int&&);
请注意,我的玩具示例在两种情况下都具有相同的长度,但两者之间存在一些差异:
在我提出的解决方案中,
std::forward<T>
std::move
,而在另一个重载中不编写任何内容。