使用除专业化之外的默认Traits

时间:2018-02-12 11:04:06

标签: c++ templates metaprogramming traits template-meta-programming

我想要做的是使用默认逻辑创建一个通用traits类,然后编写代码来专门化每个特定情况,只使用与通用情况不同的东西。我的目标是删除代码重复并避免编写不必要的代码。

我给你举个例子:

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
    }

  };

你认为理论上可以做这样的事吗?

2 个答案:

答案 0 :(得分:1)

是。将您的通用案例放在基类中:

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

答案 1 :(得分:1)

您可以使用第二个特性来完成这项工作。其目的是检查当前IdTrait<id>内每个元素的存在,并设置默认类型/函数。

对这两种类型使用当前experimental detection,为该函数使用成员getF

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

然后用这个替换你的特性:

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

<强> Demo