Skip to content

Instantly share code, notes, and snippets.

@bkietz
Last active April 5, 2019 19:26
Show Gist options
  • Save bkietz/561970db2caee4397e4b766601f2c797 to your computer and use it in GitHub Desktop.
Save bkietz/561970db2caee4397e4b766601f2c797 to your computer and use it in GitHub Desktop.
dead simple output pointer
#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_;
};
#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