我想创建一个模板类,使比较函数返回一个整数[ - 等于,> 0应该先,<0 B应该放在第一位。
我使用的排序结构模板参数来跟踪应该使用的类型,在字符串中字段的偏移量的,以及顺序,这个领域应该保持...所以比较可以根据返回正确的值。
现在假设该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)));
}
}
};
两件事情我一直没能实现。
此变得基本上更容易的,如果不是使用这种形式:
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)
等等。
我会采取另一条战线这个问题:你如何提取模板参数,如果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
}
};
这也增加了可能性,一天增加了另一种形式的,将有不同的模板参数或暴露的不同的事情。