mercredi 20 mars 2019

Carrying out traits implementation details

Initially, I have a set of some traits StandardInfo and an auxiliary wrapper template StandardTraits full of static methods doing something with info with StandardInfo:

#include <iostream>
#include <type_traits>
#include <cstdint>

template <std::uint32_t Id>
struct StandardInfo
{ };

template <>
struct StandardInfo<1>
{
    using Field1 = std::integral_constant<std::uint32_t, 42>;
};

template <>
struct StandardInfo<2>
{
    using Field1 = std::integral_constant<std::uint32_t, 19>;
};

// and more StandardInfo specifications...



template <std::uint32_t Id>
struct StandardTraits
{  
    using Info = StandardInfo<Id>;
    static void DoFoo() { std::cout << Info::Field1::value; }
};



int main()
{
    StandardTraits<1>::DoFoo();
    return 0;
}

Suppose I need to introduce another non-standard type trait. All of the StandardInfo specializations are automatically generated and I am not supposed to change that order of things. So I have to introduce NonStandartInfo trait. Therefore, I need NonStandardTraits wrapper containing same methods as in StandardTraits. It turns out that StandardTraits and NonStandardTraits differs only in Info type alias. Copy-pasting the implementation seems dubious, so it seems I need to carry out the wrapper implementation into kind of TraitsImpl and not to change existing code that already uses StandardTraits.

#include <iostream>
#include <type_traits>
#include <cstdint>

template <std::uint32_t Id>
struct StandardInfo
{ };

template <>
struct StandardInfo<1>
{
    using Field1 = std::integral_constant<std::uint32_t, 42>;
};

template <>
struct StandardInfo<2>
{
    using Field1 = std::integral_constant<std::uint32_t, 19>;
};

// and more StandardInfo specifications...

template <std::uint32_t Id>
struct NonStandardInfo
{ };

template <>
struct NonStandardInfo<1>
{
    using Field1 = std::integral_constant<int, -1>;
};

template <>
struct NonStandardInfo<2>
{
    using Field1 = std::integral_constant<int, -2>;
};

template <typename Info>
struct TraitsImpl
{
    static void DoFoo() { std::cout << Info::Field1::value; }
};

template <std::uint32_t Id>
struct StandardTraits: TraitsImpl<StandardInfo<Id> >
{  

};

template <std::uint32_t Id>
struct NonStandardTraits: TraitsImpl<NonStandardInfo<Id> >
{    
};


int main()
{
    StandardTraits<1>::DoFoo();
    NonStandardTraits<1>::DoFoo();
    return 0;
}

But doesn't it expose implementation details (via the public inheritance)? Inheriting private and proxying calls looks silly too. Is there any more elegant approach?

Aucun commentaire:

Enregistrer un commentaire