Home Using default Traits apart from the specializations
Reply: 2

Using default Traits apart from the specializations

svoltron
1#
svoltron Published in 2018-02-12 11:04:06Z

What I want to do is to create a generic traits class with the default logic and then write code to specialize each specific case with only the things that are different from the generic case. My goal is to remove code duplication and avoid writing unnecessary code.

I'll give you an example:

int genericFunction(); // defined somewhere else
int specialFunction(); // defined somewhere else

template<int id>
struct IdTraits
  {
  using MyType = int;
  using AnotherType = double;
  static constexpr auto&& f = genericFunction;
  };

template<>
struct IdTraits<1>
  {
  // Using MyType and AnotherType of IdTraits generic case [how?]
  static constexpr auto&& f = specialFunction;
  };

template<>
struct IdTraits<2>
  {
  // Using MyType and f of IdTraits generic case [how?]
  using AnotherType = char;
  };

template<int id, class Traits = IdTraits<id>>
struct General
  {
  void foo(int arg)
    {
    Traits::MyType myType;
    Traits::AnotherType anotherType;
    Traits::f(arg);
    // Do stuff with myType and anotherType
    }

  };

Do you think is theoretically possible to do something like this?

O'Neil
2#
O'Neil Reply to 2018-02-12 12:00:53Z

You can have a second Trait to use instead that will do this work. Its purpose will be to check the presence of each element inside the current IdTrait<id> and set the default type/function if not.

Using current experimental detection for the two types, and member getF for the function:

template<int id>
struct MyIdTraits {
    template <typename T> using MyType_t = typename T::MyType;
    using MyType = std::experimental::detected_or_t<int, MyType_t, IdTraits<id>>;

    template <typename T> using AnotherType_t = typename T::AnotherType;
    using AnotherType = std::experimental::detected_or_t<double, AnotherType_t, IdTraits<id>>;

    template <typename T, typename = decltype(T::f)>
    static constexpr auto getF(int) { return T::f; }
    template <typename T>
    static constexpr auto getF(unsigned) { return genericFunction; }

    static constexpr auto&& f = getF<IdTraits<id>>(42);
};

Then replace your trait by this one:

template<int id, class Traits = MyIdTraits<id>>
struct General { ... };

Demo

bolov
3#
bolov Reply to 2018-02-12 11:26:54Z

Yes. Put your generic case in a base class:

namespace details
{
struct IdTraits_generic
{
    using MyType = int;
    using AnotherType = double;
    static constexpr auto&& f = genericFunction;
};
}

template<int id> struct IdTraits : details::IdTraits_generic
{
};

template<> struct IdTraits<1> : details::IdTraits_generic
{ 
  static constexpr auto&& f = specialFunction;
};

template<> struct IdTraits<2> : details::IdTraits_generic
{
  using AnotherType = char;
};
You need to login account before you can post.

About| Privacy statement| Terms of Service| Advertising| Contact us| Help| Sitemap|
Processed in 0.329364 second(s) , Gzip On .

© 2016 Powered by mzan.com design MATCHINFO