Skip to content

Instantly share code, notes, and snippets.

@vladiant
Created June 14, 2022 17:25
Show Gist options
  • Save vladiant/9656ca99bde39b6367bb5b11751a4140 to your computer and use it in GitHub Desktop.
Save vladiant/9656ca99bde39b6367bb5b11751a4140 to your computer and use it in GitHub Desktop.
StoreRLValue
cmake_minimum_required(VERSION 3.10)
project(StoreRLValue)
add_executable(
${PROJECT_NAME}
main.cpp
)
set_target_properties(
${PROJECT_NAME}
PROPERTIES
CXX_STANDARD 17
CXX_STANDARD_REQUIRED YES
CXX_EXTENSIONS NO
)
target_compile_options(
${PROJECT_NAME}
PRIVATE
$<$<CXX_COMPILER_ID:MSVC>:/W4 /WX>
$<$<NOT:$<CXX_COMPILER_ID:MSVC>>:-Wall -Wextra -Wpedantic>
)
#include <iostream>
#include <string>
#include <variant>
// https://www.fluentcpp.com/2022/05/16/how-to-store-an-lvalue-or-an-rvalue-in-the-same-object/
template <typename T>
struct NonConstReference {
T& value_;
explicit NonConstReference(T& value) : value_(value){};
};
template <typename T>
struct ConstReference {
T const& value_;
explicit ConstReference(T const& value) : value_(value){};
};
template <typename T>
struct Value {
T value_;
explicit Value(T&& value) : value_(std::move(value)) {}
};
template <typename T>
using Storage = std::variant<Value<T>, ConstReference<T>, NonConstReference<T>>;
template <typename... Functions>
struct overload : Functions... {
using Functions::operator()...;
overload(Functions... functions) : Functions(functions)... {}
};
template <typename T>
T const& getConstReference(Storage<T> const& storage) {
return std::visit(
overload([](Value<T> const& value) -> T const& { return value.value_; },
[](NonConstReference<T> const& value) -> T const& {
return value.value_;
},
[](ConstReference<T> const& value) -> T const& {
return value.value_;
}),
storage);
}
struct NonConstReferenceFromReference : public std::runtime_error {
explicit NonConstReferenceFromReference(std::string const& what)
: std::runtime_error{what} {}
};
template <typename T>
T& getReference(Storage<T>& storage) {
return std::visit(
overload([](Value<T>& value) -> T& { return value.value_; },
[](NonConstReference<T>& value) -> T& { return value.value_; },
[](ConstReference<T>&) -> T& {
throw NonConstReferenceFromReference{
"Cannot get a non const reference from a const reference"};
}),
storage);
}
class MyClass {
public:
explicit MyClass(std::string& value) : storage_(NonConstReference(value)) {}
explicit MyClass(std::string const& value)
: storage_(ConstReference(value)) {}
explicit MyClass(std::string&& value) : storage_(Value(std::move(value))) {}
void print() const { std::cout << getConstReference(storage_) << '\n'; }
private:
Storage<std::string> storage_;
};
int main() {
{
std::string s = "hello";
MyClass myObject{s};
myObject.print();
}
{
MyClass myObject{std::string{"hello"}};
myObject.print();
}
{
const std::string s = "hello";
MyClass myObject{s};
myObject.print();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment