Commit 33fd8647 authored by Timo Koch's avatar Timo Koch

[common] Add a helper to create named equality-comparable tags

parent b79d7cdd
......@@ -40,6 +40,7 @@ splinecommon_.hh
staggeredfvproblem.hh
start.hh
tabulated2dfunction.hh
tag.hh
timeloop.hh
timemanager.hh
valgrind.hh
......
// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
// vi: set et ts=4 sw=4 sts=4:
/*****************************************************************************
* See the file COPYING for full copying permissions. *
* *
* This program 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. *
* *
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>. *
*****************************************************************************/
/*!
* \file
* \ingroup Common
* \brief Helper class to create (named and comparable) tagged types
*/
#ifndef DUMUX_COMMON_TAG_HH
#define DUMUX_COMMON_TAG_HH
#include <sstream>
#include <ostream>
#include <type_traits>
#include <dune/common/classname.hh>
#include <dumux/common/typetraits/isvalid.hh>
namespace Dumux::Utility {
/*!
* \ingroup Common
* \brief Helper class to create (named and comparable) tagged types
* Tags any given type. The tagged type is equality comparable and can be written to streams.
* A custom name can be provided by implementing the `name()` member function.
*/
template<class T>
struct Tag {};
//! Tags are equality comparable and return true if the tagged types are equal
template<class T1, class T2>
inline constexpr bool operator==(Tag<T1>, Tag<T2>)
{ return std::is_same_v<T1, T2>; }
template<class T1, class T2>
inline constexpr bool operator!=(Tag<T1>, Tag<T2>)
{ return !std::is_same_v<T1, T2>; }
namespace Detail {
constexpr auto hasName = isValid([](auto&& t) -> decltype(t.name(), void()) {});
} // end namespace Detail
//! Return the class name of the tagged type calling t.name()
template<class T, std::enable_if_t<std::is_base_of_v<Tag<T>, T>, int> = 0>
auto operator<<(std::ostream& os, const T& t)
-> std::enable_if_t<decltype(Detail::hasName(t))::value, std::ostream&>
{ os << t.name(); return os; }
//! Return the class name of the tagged type calling Dune::className if t.name() doesn't exist
template<class T, std::enable_if_t<std::is_base_of_v<Tag<T>, T>, int> = 0>
auto operator<<(std::ostream& os, const T& t)
-> std::enable_if_t<!decltype(Detail::hasName(t))::value, std::ostream&>
{
const auto fullName = Dune::className<T>();
// strip all namespace qualifiers
const auto pos = fullName.rfind("::");
const auto name = pos != std::string::npos ? fullName.substr(pos+2) : fullName;
os << name;
return os;
}
} // end namespace Dumux::Utility
#endif
......@@ -9,3 +9,4 @@ add_subdirectory(typetraits)
dumux_add_test(SOURCES test_partial.cc LABELS unit)
dumux_add_test(SOURCES test_enumerate.cc LABELS unit)
dumux_add_test(SOURCES test_tag.cc LABELS unit)
#include <config.h>
#include <iostream>
#include <dune/common/exceptions.hh>
#include <dumux/common/tag.hh>
namespace Dumux {
struct T1 : public Utility::Tag<T1> {};
struct T2 : public Utility::Tag<T2> { std::string name() const { return "customname_t2"; }};
} // end namespace Dumux
int main(int argc, char* argv[])
{
using namespace Dumux;
T1 t11, t12;
T2 t2;
static_assert(t11 == t12, "Same tags not equal!");
static_assert(t11 != t2, "Different tags should not be equal!");
{
std::stringstream s; s << t11;
if (s.str() != "T1")
DUNE_THROW(Dune::Exception, "Wrong name: " << s.str() << ", expected: T1.");
}{
std::stringstream s; s << t2;
if (s.str() != "customname_t2")
DUNE_THROW(Dune::Exception, "Wrong name: " << s.str() << ", expected: customname_t2.");
}
return 0;
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment