Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

c++ check for nested typedef of a template parameter to get its scalar base type

Consider the exponential smoother template class below. This class is for smoothing/filtering sequential data exponentially (see update method). Elemtype might be an vector and Floattype is usually a scalar. E.g.

ExponentialSmoother<Eigen::Vector2f, float> x(0.1, Vector2f(0.5, 0.5));

In this example the second template parameter Floattype could be avoided because Eigen's Matrix class contains a nested typedef to get the scalar base type:

Vector2f::Scalar

It is also reasonable to instantiate both Elemtype and Floatype as floats to smooth one dimensional data. In this case the second template paramater could also be skipped.

template <class Elemtype, class Floattype>
class ExponentialSmoother
{
public:
    // ctor
    ExponentialSmoother(Floattype alpha, Elemtype& initial_estimate);

    // getters
    inline const Elemtype& getValue() const {return estimate_;}
    inline const Floattype getAlpha() const {return alpha_;}

    const Elemtype& update(const Elemtype& curr)
    {
       estimate_ = (alpha_ * curr) + (((Floattype)1-alpha) * estimate_);
       return estimate_;
    }

private:
    Elemtype estimate_;
    Floattype alpha_;  // smoothing factor within [0,1]
}

Now my question is what is the "most elegant" solution to implement the ExponentialSmoother with only one template parameter (the element type)? It should work with Eigen vectors and matrices but also with floating point types.

In other words, is it possible to check if Elemtype::Scalar exists and if not (i.e. Elemtype is float or double) define the Floattype as Elemtype?

A similar question has been asked here. But I am wondering what the most generic solution is if for instance STL vectors should be supported as well. Would all types require the same nested typedef (or some traits class with consistent naming)?

like image 860
spinxz Avatar asked Nov 22 '12 14:11

spinxz


1 Answers

You can use a helper. The link you gave almost contains the solution:

template<class T, class R = void>  
struct enable_if_type
{
    typedef R type;
};

template<class E, class Enable = void>
struct GetFloatType
{
    typedef E type;
};

template<class E>
struct GetFloatType<E, typename enable_if_type<typename E::Scalar>::type>
{
    typedef typename E::Scalar type;
};

Then, in your class:

template <class Elemtype, class Floattype = typename GetFloatType<Elemtype>::type>
class ExponentialSmoother
{
    // ...
};

Also, with this users can still manually provide their float type. You can see it live. Bonus: works with C++03 without problems.

Note that you can add more partial specializations of GetFloatType. Here is a live example. Don´t forget that ElemType have to be acceptable for only one specialization of GetFloatType, or else it will be ambiguous (and cause a compiler error).

like image 193
Synxis Avatar answered Oct 18 '22 19:10

Synxis