From c24a63d68ff4927fb50c765d584df9084c0fc8dd Mon Sep 17 00:00:00 2001 From: John Biddiscombe Date: Thu, 14 Mar 2013 12:06:55 +0100 Subject: [PATCH] Add a streamulus::reference wrapper for objects by reference noncopyable objects can't be streamified since the transformations invoke the copy constructor. We wrap a reference to an object inside a simple struct and streamify that, with the copy constructor passing the reference through. Note, the wrapper makes use of variadic templates to save having to 'know' the types of args required by the wrapped function () operator. for use with MSVC, the Nov 2012 CTP must be installed, or a later version if available. The CTP is available from http://www.microsoft.com/en-us/download/details.aspx?id=35515 --- src/reference.h | 69 ++++++++++++++++++++++++++++++++++++++++++++++++ src/streamulus.h | 1 + 2 files changed, 70 insertions(+) create mode 100644 src/reference.h diff --git a/src/reference.h b/src/reference.h new file mode 100644 index 0000000..aed5d4c --- /dev/null +++ b/src/reference.h @@ -0,0 +1,69 @@ +// +// reference.h +// +// Streamulus Copyright (c) 2012 Irit Katriel. All rights reserved. +// +// This file is part of Streamulus. +// +// Streamulus is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Streamulus is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Streamulus. If not, see . +// + +#pragma once + +#include // std::reference_wrapper + +namespace streamulus +{ + + // streamulus::reference + // if you attempt to Streamify(FunctionObject) something that is noncopyable, + // then compilation will fail since the copy constructor is used to move the function + // object during expression transformation. + // + // To circumvent this, one may wrap the object to be streamified using this reference + // streamulus::Streamify( streamulus::reference(instance) )(operand) + // + // This allows objects which are noncopyable, particularly those with + // some internal state which might be used in other places to be streamified directly. + // Note that this works only with the streamify variant which takes an instance of an object + // and not the templated type version, for obvious reasons. + + template + struct reference { + // output type is same as wrapped object output type + template struct result { typedef typename F::template result::type type; }; + + // construct using a supplied object, initialize our reference wrapper + inline reference(F &internal) : mInternal(internal) { +// std::cout << "streamulus_wrapper(F)" << std::endl; + } + + // copy constructor passes the reference to the new copy + inline reference(const reference &other) : mInternal(other.mInternal) { +// std::cout << "streamulus_wrapper(streamulus_wrapper(F))" << std::endl; + }; + + // we must overload the () operator and call the wrapped object () operator + // we'll use a templated parameter pack and let the compiler decide if the user + // is doing it right, since we don't know what arguments the wrapped () operater takes + template + inline typename F::template result::type operator()(Args... args) { + return mInternal.get().operator()(args...); + } + + private: + const std::reference_wrapper mInternal; + }; + +} // ns streamulus diff --git a/src/streamulus.h b/src/streamulus.h index 6528a31..1a4ad14 100644 --- a/src/streamulus.h +++ b/src/streamulus.h @@ -25,6 +25,7 @@ #include "input_stream.h" #include "operators.h" #include "streamify.h" +#include "reference.h" #include "strop_data_source.h"