mardi 19 septembre 2023

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:

#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.

Aucun commentaire:

Enregistrer un commentaire