Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

C++ template method specialization by type traits

I’m working in C++11, creating a class template. I wish to optimize certain methods according to the type traits of the template parameter (i.e. float/integer, signed/unsigned etc.). I know this could be achieved by template specialization for each specific combination of traits, but that’s too unwieldy.

Instead, I’ve got something working using the partial template specialization of a dummy struct wrapper (because so far as I’m aware partial specialization only works with structs/classes).

Working example here:

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

#include<type_traits>
#include<iostream>

template<typename T>
struct A
{
    A( T _x ) : x(_x) {}

    template<typename U, bool foobar = std::is_signed<T>::value>
    struct temp{};

    template<typename U>
    struct temp<U,true>
    {
        static constexpr U diff( A const &left, A const &right ) noexcept
        {
            std::cout << "Signed" << std::endl;
            T d = left.x - right.x;
            return d * d;
        }
    };

    template<typename U>
    struct temp<U,false>
    {
        static constexpr U diff( A const &left, A const &right ) noexcept
        {
            std::cout << "Unsigned" << std::endl;
            T d = left.x < right.x ? right.x - left.x : left.x - right.x;
            return d * d;
        }
    };

    protected:

        T x;
};

int main( int argc, char** argv )
{
    // Unsigned
    A<unsigned int> u1( 10 );
    A<unsigned int> u2( 15 );

    // Method call
    std::cout << A<unsigned int>::temp<unsigned long>::diff( u1, u2 ) << std::endl;

    // Signed
    A<float> f1( -1.23f );
    A<float> f2( 12.3f );

    // Method call
    std::cout << A<float>::temp<double>::diff( f1, f2 ) << std::endl;
}

Having to dereference the dummy struct is cumbersome from the template user’s point of view, so I’d particularly like to improve that, if possible.

My knowledge of C++ is far from encyclopedic, so I’m wondering if there are nicer solutions out there. Preferably C++11 compatible, but I’m curious to hear about alternatives in modern C++ too.

Obviously I have googled this, but it took all my search skills to get the above working.

Thanks in advance.

>Solution :

You are overcomplicating it. You can add template overloads to you class and constrain those overloads to a particular condition. For this you would use

template<typename T>
struct A
{
    A( T _x ) : x(_x) {}

    template<typename U, bool foobar = std::is_signed<T>::value>
    struct temp{};
    
    // only enabled if U or by default T is signed
    template<typename U = T, typename std::enable_if<std::is_signed<U>::value, bool>::type = true>
    static constexpr U diff( A const &left, A const &right ) noexcept
    {
        std::cout << "Signed" << std::endl;
        T d = left.x - right.x;
        return d * d;
    }

    // only enabled if U or by default T is unsigned
    template<typename U = T, typename std::enable_if<!std::is_signed<U>::value, bool>::type = true>
    static constexpr U diff( A const &left, A const &right ) noexcept
    {
        std::cout << "Unsigned" << std::endl;
        T d = left.x < right.x ? right.x - left.x : left.x - right.x;
        return d * d;
    }
    
    protected:
        T x;
};

and then your driver becomes

int main()
{
    // Unsigned
    A<unsigned int> u1( 10 );
    A<unsigned int> u2( 15 );

    // Method call
    std::cout << A<unsigned int>::diff( u1, u2 ) << std::endl;

    // Signed
    A<float> f1( -1.23f );
    A<float> f2( 12.3f );

    // Method call
    std::cout << A<float>::diff( f1, f2 ) << std::endl;
}

as seen in this live example

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading