Специализация шаблона C ++ для N + 4 типов? - PullRequest
0 голосов
/ 03 ноября 2011

У меня есть структура, подобная

template<typename T>
struct S
{
    T value;

    void Set(const T& val) { value = val; }

    void Foo();
}

T может быть int, float, char, short и long long или одним из N других POD на основе структуры.

Существует около 50 POD, и они выглядят примерно так:

struct POD1 { int i; char c; double d; }
struct POD2 { char c; double d; }
struct POD3 { POD1 p1; char s[10]; }

Мне интересно, как лучше структурировать эту договоренность. Если бы я хотел, чтобы общий случай T обрабатывал POD, мне обязательно нужно было бы предоставить четкие, конкретные определения int, float, char, short и long long?

Заранее спасибо.

1 Ответ

6 голосов
/ 03 ноября 2011

Во-первых, Set() подходит для любого базового типа, POD или агрегатного типа класса, так как последние типы классов будут иметь оператор присваивания по умолчанию, который делает то, что вам нужно.

Единственный вопрос:как звонить Foo().К счастью, у нас есть черты типа, чтобы справиться с этим, а именно: std::is_fundamental.

#include <type_traits>

template <typename T> struct S
{
  T val;

  // Base case: call member `Foo()`.    
  template <typename U, bool Primitive, bool Array> struct callFoo
  {
    static void call(const U & u) { u.Foo(); }
  };

  // Specialization for primitive types (implement this yourself)
  template <typename U> struct callFoo<U, true, false>
  {
    static void call(U u) { /* fundamental implementation here */ }
  };

  // Specialization for arrays: call `Foo()` on every element.
  template <typename U> struct callFoo<U, false, true>
  {
    typedef typename std::remove_extent<U>::type V;

    template <std::size_t N>
    static void call(const V (&arr)[N])
    {
      for (std::size_t i = 0; i != N; ++i)
      {
        callFoo<V, std::is_fundamental<V>::value, std::is_array<V>::value>::call(arr[i]);
      }
    }
  };

  void Foo()
  {
    callFoo<T, std::is_fundamental<T>::value, std::is_array<T>::value>::call(val);
  }
};

(Некоторые незначительные вещи: вы можете захотеть сделать callFoo приватным. И подумайте также о константности: если применимо,сделать callFoo и Foo` постоянными.)

...