make SFINAE templates more readable

release/4.3a0
Gerry Chen 2022-12-22 13:18:15 -05:00
parent e8ddbbebff
commit 040eb63949
No known key found for this signature in database
GPG Key ID: E9845092D3A57286
1 changed files with 61 additions and 25 deletions

View File

@ -308,26 +308,58 @@ class NoiseModelFactorN : public NoiseModelFactor {
/// N is the number of variables (N-way factor) /// N is the number of variables (N-way factor)
enum { N = sizeof...(ValueTypes) }; enum { N = sizeof...(ValueTypes) };
/// The type of the i'th template param can be obtained as ValueType<I>
template <int I, typename std::enable_if<(I < N), bool>::type = true>
using ValueType =
typename std::tuple_element<I, std::tuple<ValueTypes...>>::type;
protected: protected:
using Base = NoiseModelFactor; using Base = NoiseModelFactor;
using This = NoiseModelFactorN<ValueTypes...>; using This = NoiseModelFactorN<ValueTypes...>;
/* Like std::void_t, except produces `boost::optional<Matrix&>` instead. Used /// @name SFINAE aliases
* to expand fixed-type parameter-packs with same length as ValueTypes */ /// @{
template <typename From, typename To>
using IsConvertible =
typename std::enable_if<std::is_convertible<From, To>::value, void>::type;
template <int I>
using IndexIsValid = typename std::enable_if<(I >= 1) && (I <= N),
void>::type; // 1-indexed!
template <typename Container>
using ContainerElementType =
typename std::decay<decltype(*std::declval<Container>().begin())>::type;
template <typename Container>
using IsContainerOfKeys = IsConvertible<ContainerElementType<Container>, Key>;
/// @}
/* Like std::void_t, except produces `boost::optional<Matrix&>` instead of
* `void`. Used to expand fixed-type parameter-packs with same length as
* ValueTypes. */
template <typename T> template <typename T>
using OptionalMatrix = boost::optional<Matrix&>; using OptionalMatrix = boost::optional<Matrix&>;
/* Like std::void_t, except produces `Key` instead. Used to expand fixed-type /* Like std::void_t, except produces `Key` instead of `void`. Used to expand
* parameter-packs with same length as ValueTypes */ * fixed-type parameter-packs with same length as ValueTypes. */
template <typename T> template <typename T>
using KeyType = Key; using KeyType = Key;
public: public:
/**
* The type of the I'th template param can be obtained as ValueType<I>.
* I is 1-indexed for backwards compatibility/consistency! So for example,
* ```
* using Factor = NoiseModelFactorN<Pose3, Point3>;
* Factor::ValueType<1> // Pose3
* Factor::ValueType<2> // Point3
* // Factor::ValueType<0> // ERROR! Will not compile.
* // Factor::ValueType<3> // ERROR! Will not compile.
* ```
*/
template <int I, typename = IndexIsValid<I>>
using ValueType =
typename std::tuple_element<I - 1, std::tuple<ValueTypes...>>::type;
public:
/// @name Constructors /// @name Constructors
/// @{ /// @{
@ -353,11 +385,7 @@ class NoiseModelFactorN : public NoiseModelFactor {
* @param keys A container of keys for the variables in this factor. * @param keys A container of keys for the variables in this factor.
*/ */
template <typename CONTAINER = std::initializer_list<Key>, template <typename CONTAINER = std::initializer_list<Key>,
// check that CONTAINER is a container of Keys: typename = IsContainerOfKeys<CONTAINER>>
typename T = typename std::decay<
decltype(*std::declval<CONTAINER>().begin())>::type,
typename std::enable_if<std::is_convertible<T, Key>::value,
bool>::type = true>
NoiseModelFactorN(const SharedNoiseModel& noiseModel, CONTAINER keys) NoiseModelFactorN(const SharedNoiseModel& noiseModel, CONTAINER keys)
: Base(noiseModel, keys) { : Base(noiseModel, keys) {
assert(keys.size() == N); assert(keys.size() == N);
@ -367,10 +395,19 @@ class NoiseModelFactorN : public NoiseModelFactor {
~NoiseModelFactorN() override {} ~NoiseModelFactorN() override {}
/// Returns a key. Usage: `key<I>()` returns the I'th key. /** Returns a key. Usage: `key<I>()` returns the I'th key.
template <int I> * I is 1-indexed for backwards compatibility/consistency! So for example,
inline typename std::enable_if<(I < N), Key>::type key() const { * ```
return keys_[I]; * NoiseModelFactorN<Pose3, Point3> factor(noise, key1, key2);
* key<1>() // = key1
* key<2>() // = key2
* // key<0>() // ERROR! Will not compile
* // key<3>() // ERROR! Will not compile
* ```
*/
template <int I, typename = IndexIsValid<I>>
inline Key key() const {
return keys_[I - 1];
} }
/// @name NoiseModelFactor methods /// @name NoiseModelFactor methods
@ -433,9 +470,7 @@ class NoiseModelFactorN : public NoiseModelFactor {
/** Some optional jacobians omitted function overload */ /** Some optional jacobians omitted function overload */
template <typename... OptionalJacArgs, template <typename... OptionalJacArgs,
typename std::enable_if<(sizeof...(OptionalJacArgs) > 0) && typename = IndexIsValid<sizeof...(OptionalJacArgs) + 1>>
(sizeof...(OptionalJacArgs) < N),
bool>::type = true>
inline Vector evaluateError(const ValueTypes&... x, inline Vector evaluateError(const ValueTypes&... x,
OptionalJacArgs&&... H) const { OptionalJacArgs&&... H) const {
return evaluateError(x..., std::forward<OptionalJacArgs>(H)..., return evaluateError(x..., std::forward<OptionalJacArgs>(H)...,
@ -448,16 +483,17 @@ class NoiseModelFactorN : public NoiseModelFactor {
/** Pack expansion with index_sequence template pattern, used to index into /** Pack expansion with index_sequence template pattern, used to index into
* `keys_` and `H` * `keys_` and `H`
*/ */
template <std::size_t... Inds> template <std::size_t... Indices>
inline Vector unwhitenedError( inline Vector unwhitenedError(
boost::mp11::index_sequence<Inds...>, // boost::mp11::index_sequence<Indices...>, //
const Values& x, const Values& x,
boost::optional<std::vector<Matrix>&> H = boost::none) const { boost::optional<std::vector<Matrix>&> H = boost::none) const {
if (this->active(x)) { if (this->active(x)) {
if (H) { if (H) {
return evaluateError(x.at<ValueTypes>(keys_[Inds])..., (*H)[Inds]...); return evaluateError(x.at<ValueTypes>(keys_[Indices])...,
(*H)[Indices]...);
} else { } else {
return evaluateError(x.at<ValueTypes>(keys_[Inds])...); return evaluateError(x.at<ValueTypes>(keys_[Indices])...);
} }
} else { } else {
return Vector::Zero(this->dim()); return Vector::Zero(this->dim());