svoltron
svoltron

Reputation: 365

Using default Traits apart from the specializations

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?

Upvotes: 2

Views: 122

Answers (2)

O&#39;Neil
O&#39;Neil

Reputation: 3849

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

Upvotes: 1

bolov
bolov

Reputation: 75755

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;
};

Upvotes: 1

Related Questions