Last active
April 5, 2019 19:26
-
-
Save bkietz/561970db2caee4397e4b766601f2c797 to your computer and use it in GitHub Desktop.
dead simple output pointer
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#pragma once | |
#include <memory> | |
#include <type_traits> | |
#include <utility> | |
/// \brief out_ptr provides a low boilerplate output argument for | |
/// shared_ptr and unique_ptr values | |
template <typename T> | |
class out_ptr { | |
public: | |
using element_type = T; | |
out_ptr() = delete; | |
out_ptr(const out_ptr&) = delete; | |
out_ptr& operator=(const out_ptr&) = delete; | |
out_ptr(out_ptr&&) = default; | |
out_ptr& operator=(out_ptr&&) = default; | |
template <typename U> | |
out_ptr(std::unique_ptr<U>* unique) | |
: ptr_(unique), set_impl_(set_impl<true, U>), is_unique_(true) {} | |
template <typename U> | |
out_ptr(std::shared_ptr<U>* shared) | |
: ptr_(shared), set_impl_(set_impl<false, U>), is_unique_(false) {} | |
/// \brief set the output pointer to unique | |
void set(std::unique_ptr<element_type> unique) { | |
set_impl_(ptr_, std::move(unique)); | |
} | |
/// \brief construct an instance of element_type | |
template <typename... A> | |
void emplace(A&&... a) { | |
emplace<element_type>(std::forward<A>(a)...); | |
} | |
/// \brief construct an instance of a type which can be downcast to | |
/// element_type | |
template <typename U, typename... A> | |
void emplace(A&&... a) { | |
set(std::unique_ptr<U>(new U(std::forward<A>(a)...))); | |
} | |
private: | |
template <bool Unique, typename U> | |
using ptr_t = typename std::conditional<Unique, std::unique_ptr<U>*, | |
std::shared_ptr<U>*>::type; | |
using set_impl_t = void(void*, std::unique_ptr<element_type>); | |
template <bool Unique, typename U> | |
static void set_impl(void* ptr, std::unique_ptr<element_type> unique) { | |
*static_cast<ptr_t<Unique, U>>(ptr) = std::move(unique); | |
} | |
void* ptr_; | |
set_impl_t* set_impl_; | |
bool is_unique_; | |
}; | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <iostream> | |
#include "out_ptr.h" | |
class greeter { | |
public: | |
virtual ~greeter() = default; | |
virtual void greet() = 0; | |
}; | |
class stdout_greeter : public greeter { | |
public: | |
stdout_greeter(std::string message) : message_(std::move(message)) {} | |
void greet() override { std::cout << message_ << std::endl; } | |
static void make(std::string message, out_ptr<stdout_greeter> out) { | |
out.emplace(std::move(message)); | |
} | |
private: | |
std::string message_; | |
}; | |
void use_greeter(const std::shared_ptr<greeter>& g) { g->greet(); } | |
int main() { | |
// NB: pointer to be initialized is shared_ptr<greeter>, but the out argument | |
// is declared out_ptr<stdout_greeter>. It still just works | |
std::shared_ptr<greeter> g; | |
stdout_greeter::make("hello world", &g); | |
use_greeter(g); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment