在 C++ class 模板中表示空类型
Represents empty type in C++ class template
考虑以下 compile-time“矢量”示例。
#include <iostream>
template <int n, int...ns>
struct static_vector {
static constexpr int value = n;
static_vector<ns...> rest;
};
template <int n>
struct static_vector<n> {
static constexpr int value = n;
void* rest;
};
template <int n, class sv>
constexpr int access_nth() {
static_assert(n >= 0, "vector size out of bound");
if constexpr(n == 0) {
return sv::value;
} else {
static_assert(!std::is_same_v<decltype(sv::rest), void *>, "vector size out of bound");
return access_nth<n-1, decltype(sv::rest)>();
}
}
int main()
{
constexpr auto a = static_vector<12, 23, 34, 45>();
constexpr int nth = access_nth<5, decltype(a)>();
std::cout << nth << std::endl;
}
我对我们现在可以做的非常满意:定义一个向量,然后从中获取第 n 个元素。我发现不满意的一件事是:我必须在基本情况下使用 void *
作为虚拟对象(其中向量只包含一个元素而没有尾巴......)
我试过这样的专业:
template <>
struct static_vector<> {
}
表示空向量。但似乎编译器总是拒绝此定义并出现以下错误:
<source>:16:8: error: too few template arguments for class template 'static_vector'
struct static_vector<> {
^
我应该怎么做才能得到一个空向量?
非常感谢。
特化必须符合基本模板声明。由于基本模板至少需要一个 int
,因此无法编译。
您可以通过声明模板采用任意数量的 int
参数,然后专门化采用一个或多个参数的每个案例来实现此目的。基本声明就是空的情况:
template <int...>
struct static_vector {
// Instantiated only for the no-argument case
};
template <int n>
struct static_vector<n> {
// One-argument specialization
};
template <int n, int... ns>
struct static_vector<n, ns...> {
// Two-or-more-argument specialization
};
但为什么要递归?
你标记了 C++17 以便你可以使用模板折叠,所以...下面怎么样?
#include <iostream>
template <int ... Is>
struct static_vector
{
template <std::size_t N>
int get () const
{
static_assert( N < sizeof...(Is), "index out of bound" );
std::size_t i{};
int ret;
( ... , (N == i++ ? ret = Is : 0) );
return ret;
}
};
int main()
{
constexpr auto a = static_vector<12, 23, 34, 45>();
std::cout << a.get<3u>() << std::endl;
}
考虑以下 compile-time“矢量”示例。
#include <iostream>
template <int n, int...ns>
struct static_vector {
static constexpr int value = n;
static_vector<ns...> rest;
};
template <int n>
struct static_vector<n> {
static constexpr int value = n;
void* rest;
};
template <int n, class sv>
constexpr int access_nth() {
static_assert(n >= 0, "vector size out of bound");
if constexpr(n == 0) {
return sv::value;
} else {
static_assert(!std::is_same_v<decltype(sv::rest), void *>, "vector size out of bound");
return access_nth<n-1, decltype(sv::rest)>();
}
}
int main()
{
constexpr auto a = static_vector<12, 23, 34, 45>();
constexpr int nth = access_nth<5, decltype(a)>();
std::cout << nth << std::endl;
}
我对我们现在可以做的非常满意:定义一个向量,然后从中获取第 n 个元素。我发现不满意的一件事是:我必须在基本情况下使用 void *
作为虚拟对象(其中向量只包含一个元素而没有尾巴......)
我试过这样的专业:
template <>
struct static_vector<> {
}
表示空向量。但似乎编译器总是拒绝此定义并出现以下错误:
<source>:16:8: error: too few template arguments for class template 'static_vector'
struct static_vector<> {
^
我应该怎么做才能得到一个空向量?
非常感谢。
特化必须符合基本模板声明。由于基本模板至少需要一个 int
,因此无法编译。
您可以通过声明模板采用任意数量的 int
参数,然后专门化采用一个或多个参数的每个案例来实现此目的。基本声明就是空的情况:
template <int...>
struct static_vector {
// Instantiated only for the no-argument case
};
template <int n>
struct static_vector<n> {
// One-argument specialization
};
template <int n, int... ns>
struct static_vector<n, ns...> {
// Two-or-more-argument specialization
};
但为什么要递归?
你标记了 C++17 以便你可以使用模板折叠,所以...下面怎么样?
#include <iostream>
template <int ... Is>
struct static_vector
{
template <std::size_t N>
int get () const
{
static_assert( N < sizeof...(Is), "index out of bound" );
std::size_t i{};
int ret;
( ... , (N == i++ ? ret = Is : 0) );
return ret;
}
};
int main()
{
constexpr auto a = static_vector<12, 23, 34, 45>();
std::cout << a.get<3u>() << std::endl;
}