如何访问模板包参数的模板参数

时间:2019-02-05 19:10:38

标签: c++ templates c++17

我正在尝试创建一个模板类,使比较函数返回整数[0-相等,> 0 a首先出现,<0 b首先出现]。

我正在使用Sort structs模板参数来跟踪应使用的类型,字符串中字段的偏移量以及应保留该字段的顺序...所以比较可以根据返回正确的值。

现在假设std::string用于表示序列化的值。

我无法从模板中提取信息。我将sort保留为pack参数,其类型为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)的总和。
  • 每次调用内部比较运算符。

Link to code on compiler explorer

2 个答案:

答案 0 :(得分:2)

我将在另一个方面解决这个问题:如果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参数,从而使界面更灵活:

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

这也增加了一天添加另一种可能具有不同模板参数或暴露出不同事物的可能性的可能性。

答案 1 :(得分:2)

如果不使用这种形式,这将变得相当容易:

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)

依此类推。