На главную Наши проекты:
Журнал   ·   Discuz!ML   ·   Wiki   ·   DRKB   ·   Помощь проекту
ПРАВИЛА FAQ Помощь Участники Календарь Избранное RSS
msm.ru
Модераторы: Qraizer, Hsilgos
  
> Проблема с частичной специализацией для массивов/контейнеров.
    Всем привет.

    Не получается сделать специализацию для контейнеров.
    Для массива работает, для std::array/std::vector не хочет.
    Вот есть такой код, никак понять не могу - как его специализировать для контейнеров?
    ExpandedWrap disabled
      template<typename T, typename R> struct Euclidean
      {
         static inline R Distance(T q, T p)
         {
            auto diff = q - p;
            return static_cast<R>(std::sqrt( diff*diff ));
         }
      };
       
      //! For arrays
      template<typename T, typename R, size_t Size>
      struct Euclidean<R, T[Size]>
      {
         using Type = T[Size];
         static inline R Distance(Type q, Type p)
         {
            R RetVal = R();
            for (auto i = 0u; i < Size; ++i)
            {
               RetVal += (q[i] - p[i]) * (q[i] - p[i]);
            }
            return static_cast<R>(std::sqrt(RetVal));
         }
      };
       
      //! For containers
      template< template<typename> typename T, typename R>
      struct Euclidean<T<R>, R>
      {
         static inline R Distance(T<R> q, T<R> p)
         {
            R RetVal = R();
            for (auto i = 0u; i < std::size(q); ++i)
            {
               RetVal += (q[i] - p[i]) * (q[i] - p[i]);
            }
            return static_cast<R>(std::sqrt(RetVal));
         }
      };
       
      int main()
      {
         float q[4] = { 1,2,3,4 };
         float p[4] = { 5,6,7,8 };
       
         using TVectori = std::array<unsigned int, 4u>;
       
         std::vector<float> qv = { 5,6,7,8 };
         std::vector<float> pv = { 5,6,7,8 };
         std::array<float, 4u> qa = { 5,6,7,8 };
         std::array<float, 4u> pa = { 5,6,7,8 };
       
       
         std::cout << Euclidean<float, float>::Distance(4.f, 5.f) << std::endl;
         std::cout << Euclidean<float, float[4]>::Distance(q, p) << std::endl;
         std::cout << Euclidean<std::vector<float>, float>::Distance(qv, pv) << std::endl;
         std::cout << Euclidean<std::array<float, 4u>, float>::Distance(qa, pa) << std::endl;
         std::cin.get();
         return 0;
      }

    У меня почему то пытается вызваться базовая версия шаблона.

    Спасибо.
    Сообщение отредактировано: Wound -
      Я думаю тебе должна помочь эта статейка.
        Цитата Wound @
        Не получается сделать специализацию для контейнеров.
        Для массива работает, для std::array/std::vector не хочет.

        У std::vector два параметра шаблона. Надо делать template< template<typename, typename> typename T, typename R> или что-то типа того
          И это тоже. И исходники этого подсмотреть.

          Вощем, считай, просто - чуйка, ошибаться право имею :lol:
            Цитата Олег М @
            У std::vector два параметра шаблона. Надо делать template< template<typename, typename> typename T, typename R> или что-то типа того

            Пробовал, тогда не понятно что передавать в список аргументов:
            ExpandedWrap disabled
              template< template<typename, typename> typename T, typename R>
              struct Euclidean<T<R, ?>, R>
              {
                 static inline R Distance(const T<R,?>& q, const T<R,?>& p)
                 {
                    R RetVal = R();
                    for (auto i = 0u; i < std::size(q); ++i)
                    {
                       RetVal += (q[i] - p[i]) * (q[i] - p[i]);
                    }
                    return static_cast<R>(std::sqrt(RetVal));
                 }
              };


            Цитата JoeUser @
            Я думаю тебе должна помочь эта статейка.

            Ща гляну.
            Сообщение отредактировано: Wound -
              Цитата Wound @
              Пробовал, тогда не понятно что передавать в список аргументов:


              struct Euclidean<T<R, std::allocator<R>>, R>
                Цитата Олег М @
                struct Euclidean<T<R, std::allocator<R>>, R>

                Да, заработало. Спасибо.

                Добавлено
                А еще такой вопрос, вот по сути тут передается вектор и std::array, у которых два шаблонных параметра. Если переписывать на вариадики, то должно получится примерно вот так(чтоб не писать для каждого контейнера специализацию)?
                ExpandedWrap disabled
                  template< template<typename ...> typename T, typename R, typename ... Args>
                  struct Euclidean<T<R, Args...>, R>
                  {
                     static inline R Distance(const T<R, Args...>& q, const T<R, Args...>& p)
                     {
                        R RetVal = R();
                        for (auto i = 0u; i < std::size(q); ++i)
                        {
                           RetVal += (q[i] - p[i]) * (q[i] - p[i]);
                        }
                        return static_cast<R>(std::sqrt(RetVal));
                     }
                  };


                Добавлено
                Не, для std::array вариадик не прокатил, только для вектора и ему подобных. Видимо все таки для std::array нужна отдельная специализация.
                Получилось вот так:
                ExpandedWrap disabled
                  template<typename T, typename R, std::size_t N>
                  struct Euclidean<std::array<T, N>, R>
                  {
                     using TArray = std::array<T, N>;
                     static inline R Distance(const TArray& q, const TArray& p)
                     {
                        R RetVal = R();
                        for (auto i = 0u; i < std::size(q); ++i)
                        {
                           RetVal += (q[i] - p[i]) * (q[i] - p[i]);
                        }
                        return static_cast<R>(std::sqrt(RetVal));
                     }
                  };
                   
                  template< template<typename ...> typename T, typename R, typename ... Args>
                  struct Euclidean<T<R, Args...>, R>
                  {
                     using TContainer = T<R, Args...>;
                     static inline R Distance(const TContainer& q, const TContainer& p)
                     {
                        R RetVal = R();
                        for (auto i = 0u; i < std::size(q); ++i)
                        {
                           RetVal += (q[i] - p[i]) * (q[i] - p[i]);
                        }
                        return static_cast<R>(std::sqrt(RetVal));
                     }
                  };
                  Цитата Wound @
                  template< template<typename ...> typename T, typename R, typename ... Args>
                  struct Euclidean<T<R, Args...>, R>
                  {
                     static inline R Distance(const T<R, Args...>& q, const T<R, Args...>& p)
                     {
                        R RetVal = R();
                        for (auto i = 0u; i < std::size(q); ++i)
                        {


                  Здесь лучше делать через итераторы - begin/end, а то для std::list не будет работать, да и размерность массивов может быть разная.
                  0 пользователей читают эту тему (0 гостей и 0 скрытых пользователей)
                  0 пользователей:


                  Рейтинг@Mail.ru
                  [ Script execution time: 0,0296 ]   [ 16 queries used ]   [ Generated: 28.03.24, 09:48 GMT ]