使用除专业之外的默认特征

Using default Traits apart from the specializations

我想做的是创建一个具有默认逻辑的通用特征 class,然后编写代码以专门化每个特定案例,仅包含与通用案例不同的内容。我的目标是消除代码重复并避免编写不必要的代码。

我举个例子:

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
    }

  };

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

是的。将您的通用案例放在基础 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;
};

您可以使用第二个 Trait 来完成这项工作。它的目的是检查当前 IdTrait<id> 中每个元素的存在,如果没有则设置默认的 type/function。

两种类型使用current experimental detection,函数使用member 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