// ccutl.arg feature guard {{{
#ifndef CCUTL_ARG_INCLUDED
#define CCUTL_ARG_INCLUDED
// ccutl.arg feature guard }}}
/* C++20
| |
__| __| | | __| |
( ( | | | |
\___| \___| \__,_| \__| _|
ccutl Core Utilities
[ccutl.arg]: returns the passed arg by index, preserving reference qualifier
Copyright (C) 2020, 2021 Justin Collier
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 internalied 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 . */
#include
#ifndef CCUTL_NAMESPACE
#define CCUTL_NAMESPACE ctl
#endif
namespace CCUTL_NAMESPACE {
// ccutl.rmref {{{
// ccutl.rmref feature guard {{{
#ifndef CCUTL_RMREF_INCLUDED
#define CCUTL_RMREF_INCLUDED
// ccutl.rmref feature guard }}}
/**
* shorthand for std::remove_reference_t
*
* \anchor rmref
* \ingroup ccutl
*/
template
using rmref = std::remove_reference_t;
// ccutl.rmref version guard {{{
#define CCUTL_RMREF_VERSION_MAJOR 0
#define CCUTL_RMREF_VERSION_MINOR 3
#define CCUTL_RMREF_VERSION_PATCH 2
#elif CCUTL_RMREF_VERSION_MAJOR != 0
#error ccutl.rmref major version mismatch
#elif CCUTL_RMREF_VERSION_MINOR != 3
#error ccutl.rmref minor version mismatch
#elif CCUTL_RMREF_VERSION_PATCH != 2
#warning ccutl.rmref patch version mismatch
#endif
// ccutl.rmref version guard }}}
// ccutl.rmref }}}
// ccutl.fwd {{{
// ccutl.fwd feature guard {{{
#ifndef CCUTL_FWD_INCLUDED
#define CCUTL_FWD_INCLUDED
// ccutl.fwd feature guard }}}
/*
note: the following was copied from the C++ standard draft GitHub sources
https://github.com/cplusplus/draft.git 60a9591
©ISO/IEC
20.2.4 forward/move helpers [forward]
1 The library provides templated helper functions to simplify applying move
semantics to an lvalue and to simplify the implementation of forwarding
functions. All functions specified in this subclause are signal-safe
(17.13.4).
template constexpr T&& forward(remove_reference_t& t) noexcept;
template constexpr T&& forward(remove_reference_t&& t) noexcept;
2 Mandates: For the second overload, is_lvalue_reference_v is false.
3 Returns: static_cast(t).
*/
/**
* perfect forwarder for lvalues
*
* \anchor fwd
* \ingroup ccutl
*/
template
constexpr T&&
fwd(rmref& t) noexcept {
return static_cast(t);
}
/**
* perfect forwarder for rvalues
*
* \anchor fwd
* \ingroup ccutl
*/
template
constexpr T&&
fwd(rmref&& t) noexcept {
static_assert(
!std::is_lvalue_reference_v,
"cannot instantiate an rvalue forwarder with an lvalue reference type");
return static_cast(t);
}
// ccutl.fwd version guard {{{
#define CCUTL_FWD_VERSION_MAJOR 0
#define CCUTL_FWD_VERSION_MINOR 3
#define CCUTL_FWD_VERSION_PATCH 2
#elif CCUTL_FWD_VERSION_MAJOR != 0
#error ccutl.fwd major version mismatch
#elif CCUTL_FWD_VERSION_MINOR != 3
#error ccutl.fwd minor version mismatch
#elif CCUTL_FWD_VERSION_PATCH != 2
#warning ccutl.fwd patch version mismatch
#endif
// ccutl.fwd version guard }}}
// ccutl.fwd }}}
/* */ // clang-format off
// detail {{{
namespace detail {
namespace arg {
/// lvalue forwarder for final arg result
template
requires (targ == i) && (std::is_lvalue_reference_v)
[[nodiscard]] inline constexpr First &
impl(First&& first, Rest &&...) noexcept {
return fwd(first);
}
/// rvalue forwarder for final arg result
template
requires (targ == i) && (std::is_rvalue_reference_v)
[[nodiscard]] inline constexpr First &&
impl(First&& first, Rest &&...) noexcept {
return fwd(first);
}
/// recursively pop_front arguments until incrementation is completed
template
requires (targ != i)
[[nodiscard]] inline constexpr auto &&
impl(First &&, Rest &&... rest) noexcept {
return impl(fwd(rest)...);
}
/// checks if idx is within range to be able to index Ts
template
inline constexpr bool
valid_indexable_pack = sizeof...(Ts) > 0 && idx < sizeof...(Ts);
} // namespace arg
} // namespace detail
// detail }}}
/**
* returns the passed arg by index, preserving reference qualifier
*
* \code
* #include "ctl/arg.h"
*
* char c = 'c';
* auto &&x0 = ctl::arg<0>('a', "b", c); // (char) 'a'
* auto &&x1 = ctl::arg<1>('a', "b", c); // (char const*) "b"
* auto &&x2 = ctl::arg<2>('a', "b", c); // (char &) c
* \endcode
*
* \anchor arg
* \ingroup ccutl
*/
template
requires detail::arg::valid_indexable_pack
[[nodiscard]] inline constexpr auto &&
arg(Ts &&... args) noexcept {
return detail::arg::impl(fwd(args)...);
}
/* */ // clang-format on
} // namespace CCUTL_NAMESPACE
// ccutl.arg version guard {{{
#define CCUTL_ARG_VERSION_MAJOR 0
#define CCUTL_ARG_VERSION_MINOR 3
#define CCUTL_ARG_VERSION_PATCH 2
#elif CCUTL_ARG_VERSION_MAJOR != 0
#error ccutl.arg major version mismatch
#elif CCUTL_ARG_VERSION_MINOR != 3
#error ccutl.arg minor version mismatch
#elif CCUTL_ARG_VERSION_PATCH != 2
#warning ccutl.arg patch version mismatch
#endif
// vim: fmr={{{,}}} fdm=marker
// ccutl.arg version guard }}}