Как получить доступ к параметрам шаблона параметра пакета шаблона - PullRequest
0 голосов
/ 05 февраля 2019

Я пытаюсь создать шаблонный класс, который позволит функции сравнения возвращать целое число [0 - равно,> 0 a должно идти первым, <0 b должно идти первым]. </p>

Я используюСортировать структурирует параметры шаблона для отслеживания типа, который следует использовать, смещения поля в строке, а также порядка сохранения этого поля ... так что сравнение может соответственно вернуть правильное значение.

Предположим, что std::string используется для представления сериализованного значения.

У меня проблемы с извлечением информации из шаблона.Я сохранил sort в качестве параметра пакета, который будет иметь тип Sort.Как мне получить доступ к этим параметрам в коде?Если есть лучший способ реорганизовать это.Я посмотрел на некоторые другие вопросы, связанные с шаблонами, но не увидел ни одного, который мог бы решить эту проблему.Я использую gcc 8.2 и c ++ 17.

#include <cstdint>
#include <string>
#include <cstring>
#include <cassert>

template<typename T, uint32_t offset, char Order = 'A'>
struct Sort {};

template<uint32_t keyLength, template<typename T,uint32_t offset, char Order> class ... sort>
class Comparator {
public:
      int compare(std::string & a, std::string &b) {
         assert(a.length()==b.length());
         // How would I sum the sizeof each T. i.e. if T is int and another T is short, then sum should be 6+keyLength?
         assert(a.length()==(sizeof(T)+keyLength)); // Check that my length is equal to key length + all type lengths put together
         auto r = memcmp(a.data(),b.data(),keyLength);
         if(r!=0) return r;
         // How do I retrieve T,offset,Order of each pack parameter.
         return internal_compare<T,offset,Order>(a.data(),b.data())? internal_compare<T,offset,Order>(a.data(),b.data()) : ...;

      }

private:
      template<typename IT,uint32_t iOffset, char iOrder>
      int internal_compare(char * a,char *b) {
         if constexpr (iOrder=='A'||iOrder=='a') {
            return (*(static_cast<IT *>(a+iOffset)))-(*(static_cast<IT *>(b+iOffset)));
         } else {
            return (*(static_cast<IT *>(b+iOffset)))-(*(static_cast<IT *>(a+iOffset)));
         }
      }
};

Две вещи, которые мне не удалось выполнить.

  • Каждый получает сумму sizeof (T) из сортировки.
  • Вызовите внутренний оператор сравнения для каждой сортировки.

Ссылка на код в проводнике компилятора

Ответы [ 2 ]

0 голосов
/ 06 февраля 2019

Это становится значительно проще, если вместо использования этой формы:

template<typename T, uint32_t offset, char Order = 'A'>
struct Sort {};

template<uint32_t keyLength, template<typename T,uint32_t offset, char Order> class ... sort>
class Comparator;

Вы используете эту:

template <uint32_t keyLength, class...>
class Comparator;

template <uint32_t keyLength, typename... T, uint32_t... offset, char... Order>
class Comparator<keyLength, Sort<T, offset, Order>...> {
    // ...
};

Во-первых, оригинал не сделал то, что вы хотели сделатьтем не мение.Вы хотели конкретные экземпляры Sort, но вы на самом деле принимали шаблоны классов ... как Comparator<32, Sort, Sort, Sort>.Что, по-видимому, не имеет смысла.

Но когда мы делаем это таким образом, мы не только принимаем только экземпляры Sort, но и имеем параметры в наиболее полезной форме.Так что-то вроде этого:

// How would I sum the sizeof each T. i.e. if T is int and another T is short,
// then sum should be 6+keyLength?

- это выражение сгиба:

(sizeof(T) + ... + keyLength)

и т. Д.

0 голосов
/ 05 февраля 2019

Я перейду к этой проблеме с другой стороны: как извлечь параметры шаблона, если T имеет параметры шаблона?Вот пример:

template<typename T>
void foo(T v) {
    // T is std::vector<int>, how to extract `int`?
}

int main() {
    foo(std::vector{1, 2, 3, 4});
}

На это есть много ответов: извлечение с использованием частичной специализации, псевдонимы типов и др.

Вот как это можно сделать для std::vector:

template<typename>
struct extract_value_type_t {};

template<typename T>
struct extract_value_type_t<std::vector<T>> {
    using type = T;
};

template<typename T>
using extract_value_type_t = typename extract_value_type<T>::type;

template<typename T>
void foo(T v) {
    // with template specialization
    using value_type = extract_value_type_t<T>;

    // with the member alias std::vector exposes
    // needs much less boilerplate!
    using value_type = typename T::value_type;
}

Что делает это с T, когда нам дает вектор?Что ж, если вы можете сделать что-то с простым типом T, вам даже не понадобится параметр шаблона шаблона, что сделает ваш интерфейс более гибким:

template<typename>
struct sort_traits {};

template<typename T, uint32_t offset_, char order_>
struct sort_traits<Sort<T, offset_, order_>> {
    using type = T
    static constexpr auto offset = offset_;
    static constexpr auto order = order_;
};

Тогда в вашем классе Comparator простосделайте что-то вроде этого:

template<uint32_t keyLength, typename... sorts>
struct Comparator {
    int compare(std::string const& a, std::string const& b) {
       return (internal_compare<sorts>(a.data(), b.data()) && ...);
    }

private:
    template<typename sort>
    int internal_compare(char const* a, char const* b) {
       using traits = sort_traits<sort>;
       using type = typename traits::type;
       constexpr auto offset = traits::offset;
       constexpr auto order = traits::order;

       // do stuff
    }
};

Это также добавит возможность однажды добавить другой вид сортировки, который будет иметь другие параметры шаблона или другие объекты.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...