add a simple helper class that allows to store data members conditionally

the class takes a boolean parameter as its first template parameter
and a type name as the second. if the boolean parameter is false,
nothing is stored, else an object of the type of the second template
parameter gets created. this mechanism allows to disable member
attributes based on compile time conditions.

The usage semantics of that class are that of a smart pointer class, i.e.,
the equivalent of

```
Foo foo;
foo.bar()
```

is

```
Opm::ConditionalStorage<true, Foo> foo;
foo->bar();
```

If the condition argument for the ConditionalStorage is false, that
code will still compile but an exception is thrown at runtime.
This commit is contained in:
Andreas Lauser 2017-11-23 14:34:02 +01:00
parent a346cf5e16
commit 0b097b60f4
2 changed files with 168 additions and 0 deletions

View File

@ -57,6 +57,7 @@ list (APPEND PROGRAM_SOURCE_FILES
list( APPEND PUBLIC_HEADER_FILES
opm/common/ConditionalStorage.hpp
opm/common/ErrorMacros.hpp
opm/common/Exceptions.hpp
opm/common/ResetLocale.hpp

View File

@ -0,0 +1,167 @@
// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
// vi: set et ts=4 sw=4 sts=4:
/*
This file is part of the Open Porous Media project (OPM).
OPM 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 2 of the License, or
(at your option) any later version.
OPM 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 OPM. If not, see <http://www.gnu.org/licenses/>.
Consult the COPYING file in the top-level source directory of this
module for the precise wording of the license and the list of
copyright holders.
*/
/*!
* \file
*
* \copydoc Opm::ConditionalStorage
*/
#ifndef OPM_CONDITIONAL_STORAGE_HH
#define OPM_CONDITIONAL_STORAGE_HH
#include <opm/common/ErrorMacros.hpp>
#include <opm/common/Exceptions.hpp>
#include <opm/common/Unused.hpp>
#include <utility>
namespace Opm {
/*!
* \ingroup Common
*
* \brief A simple class which only stores a given member attribute if a boolean
* condition is true
*
* If the condition is false, nothing is stored and an exception is thrown when trying to
* access the object.
*/
template <bool cond, class T>
class ConditionalStorage
{
public:
typedef T type;
static constexpr bool condition = cond;
ConditionalStorage()
{}
ConditionalStorage(const T& v)
: data_(v)
{}
ConditionalStorage(T&& v)
: data_(std::move(v))
{}
template <class ...Args>
ConditionalStorage(Args... args)
: data_(args...)
{}
ConditionalStorage(const ConditionalStorage& t)
: data_(t.data_)
{};
ConditionalStorage(ConditionalStorage&& t)
: data_(std::move(t.data_))
{};
ConditionalStorage& operator=(const ConditionalStorage& v)
{
data_ = v.data_;
return *this;
}
ConditionalStorage& operator=(ConditionalStorage&& v)
{
data_ = std::move(v.data_);
return *this;
}
const T& operator*() const
{ return data_; }
T& operator*()
{ return data_; }
const T* operator->() const
{ return &data_; }
T* operator->()
{ return &data_; }
private:
T data_;
};
template <class T>
class ConditionalStorage<false, T>
{
public:
typedef T type;
static constexpr bool condition = false;
ConditionalStorage()
{
// ensure that T has a default constructor without actually calling it
if (false) {
T OPM_UNUSED dummy; // <- if the compiler bails out here, T does not have a default constructor
}
}
ConditionalStorage(const T& v)
{
// ensure that T has a default constructor without actually calling it
if (false) {
T OPM_UNUSED dummy(v); // <- if the compiler bails out here, T does not have a copy constructor
}
}
ConditionalStorage(const ConditionalStorage &)
{
// copying an empty conditional storage object does not do anything.
};
template <class ...Args>
ConditionalStorage(Args... args)
{
// ensure that the arguments are valid without actually calling the constructor
// of T
if (false) {
T OPM_UNUSED dummy(args...); // <- if the compiler bails out here, T does not have the requested constructor
}
}
ConditionalStorage& operator=(const ConditionalStorage& v)
{
// ensure that the stored object can actually be assined to but not actually do
// anything
if (false) {
T *dummy;
(*dummy) = (*dummy); // <- if the compiler bails out here, T does not have an assignment operator
}
return *this;
}
const T& operator*() const
{ OPM_THROW(std::logic_error, "data member deactivated"); }
T& operator*()
{ OPM_THROW(std::logic_error, "data member deactivated"); }
const T* operator->() const
{ OPM_THROW(std::logic_error, "data member deactivated"); }
T* operator->()
{ OPM_THROW(std::logic_error, "data member deactivated"); }
};
} // namespace Opm
#endif