c ++检查类型是否是模板中的固定字符数组
c++ check if a type is a fixed char array in a template
我需要对正在编写的模板中的字符串类型进行一些特殊处理,但我 运行 遇到了固定大小 char 数组的问题。我知道我可以编写此答案中提到的代码来创建包装器:Const char array with template argument size vs. char pointer
但我想知道是否有一种方法可以从带有静态断言的模板函数中测试这是否是一个 const char 数组,如下所示:
template<typename T>
void f(T& val /* a handful of other params */ )
{
static_assert(
std::is_same_v < T, const char* > ||
std::is_same_v < T, char[N] > || // how do I get/discard N here?
std::is_same_v < T, std::string >
, "Unsupported type" );
}
我这样做的动机是避免为所有有效类型组合使用大量函数签名,同时仍然确保只允许有效类型。出于某些原因,编写所有这些类型声明和定义是一场噩梦。但是由于字符串可以出现在各种固定大小的数组中,我不确定如何在没有包装器的情况下检查它们以剥离长度数据,但后来我又回到编写大量包装器,这正是我试图避免的(如果有某种方法可以使用单个包装器编写一个简单的可重用测试,那没问题,但我还没有想出一个)。对于像这样的每个字符串,如果我每次都在参数列表中出现一个字符串参数时手动添加一个包装器,这显然会使我需要编写的声明和定义的数量增加一倍,从而产生大量冗余代码。那么有什么方法可以确定一个类型是否是固定数组类型,然后才提取没有长度的指针,以便我可以根据 const char* 检查它?或者以某种方式忽略数组长度,只检查它是否是我的断言中的 char 类型数组?
您无法直接确定 T
是否是数组,但标准库提供了用于确定给定类型是否已经是数组的特征:std::is_array
.
虽然std::is_array
也接受char[]
,这可能是不可取的。在这种情况下,如果您可以访问 C++20,则可以使用 std::is_bounded_array
。如果您无权访问 C++20,实现一个是相当微不足道的,或者如果您只想检查 char[N]
:
template <class> struct is_bounded_char_array : std::false_type {};
template <size_t N>
struct is_bounded_char_array<char[N]> : std::true_type {};
template <class> struct is_bounded_array : std::false_type {};
template <class T, size_t N>
struct is_bounded_array<T[N]> : std::true_type {};
static_assert(!is_bounded_array<char>{});
static_assert(!is_bounded_array<char[]>{});
static_assert(is_bounded_array<char[42]>{});
然后,您可以说 is_bounded_array<T>
,而不是 std::is_same_v < T, char[N] >
。
要从您的任何类型中获得 const char*
,您可以使用 std::string_view(t).data()
而不是自己处理每个案例。
由于类型衰减,这是不可能的; T 的结果类型(来自函数 foo)是 char*。你可以通过我的例子弄明白,试着编译它:
#include <type_traits>
template<typename T>
struct is_inbuild_array final : std::false_type{};
template<typename T, std::size_t N>
struct is_inbuild_array<T[N]> final : std::true_type{};
template<typename T>
void f(T val)
{
static_assert(
is_inbuild_array<T>::value,
"Unsupported type"
);
}
int main()
{
char array [] = "Test";
f(array);
}
但是你可以像这样修改你的函数(使用通用参考):
template<typename T>
void f(T&& val)
{
static_assert(
is_inbuild_array<std::remove_reference_t<T>>::value,
"Unsupported type"
);
}
而且效果很好
我最终这样做是为了根据此处的其他答案实施检测:
#include <type_traits>
template < typename Desired, typename Actual > struct is_bounded_type_array : std::false_type {};
template < typename Desired, typename Actual, std::size_t N >
struct is_bounded_type_array < Desired, Actual[N] > : std::conditional_t < std::is_same_v < Actual, Desired >, std::true_type, std::false_type > {};
template < typename Desired, typename Actual >
inline constexpr bool is_bounded_type_array_v = is_bounded_type_array < Desired, Actual > ::value;
然后我可以在我的函数中像这样使用它:
template<typename T>
void test(const T& value)
{
std::cout << is_bounded_type_array_v<char, T> << std::endl;
// or
static_assert(is_bounded_type_array_v<char, T>, "Must be bounded array of type char");
}
我需要对正在编写的模板中的字符串类型进行一些特殊处理,但我 运行 遇到了固定大小 char 数组的问题。我知道我可以编写此答案中提到的代码来创建包装器:Const char array with template argument size vs. char pointer
但我想知道是否有一种方法可以从带有静态断言的模板函数中测试这是否是一个 const char 数组,如下所示:
template<typename T>
void f(T& val /* a handful of other params */ )
{
static_assert(
std::is_same_v < T, const char* > ||
std::is_same_v < T, char[N] > || // how do I get/discard N here?
std::is_same_v < T, std::string >
, "Unsupported type" );
}
我这样做的动机是避免为所有有效类型组合使用大量函数签名,同时仍然确保只允许有效类型。出于某些原因,编写所有这些类型声明和定义是一场噩梦。但是由于字符串可以出现在各种固定大小的数组中,我不确定如何在没有包装器的情况下检查它们以剥离长度数据,但后来我又回到编写大量包装器,这正是我试图避免的(如果有某种方法可以使用单个包装器编写一个简单的可重用测试,那没问题,但我还没有想出一个)。对于像这样的每个字符串,如果我每次都在参数列表中出现一个字符串参数时手动添加一个包装器,这显然会使我需要编写的声明和定义的数量增加一倍,从而产生大量冗余代码。那么有什么方法可以确定一个类型是否是固定数组类型,然后才提取没有长度的指针,以便我可以根据 const char* 检查它?或者以某种方式忽略数组长度,只检查它是否是我的断言中的 char 类型数组?
您无法直接确定 T
是否是数组,但标准库提供了用于确定给定类型是否已经是数组的特征:std::is_array
.
虽然std::is_array
也接受char[]
,这可能是不可取的。在这种情况下,如果您可以访问 C++20,则可以使用 std::is_bounded_array
。如果您无权访问 C++20,实现一个是相当微不足道的,或者如果您只想检查 char[N]
:
template <class> struct is_bounded_char_array : std::false_type {};
template <size_t N>
struct is_bounded_char_array<char[N]> : std::true_type {};
template <class> struct is_bounded_array : std::false_type {};
template <class T, size_t N>
struct is_bounded_array<T[N]> : std::true_type {};
static_assert(!is_bounded_array<char>{});
static_assert(!is_bounded_array<char[]>{});
static_assert(is_bounded_array<char[42]>{});
然后,您可以说 is_bounded_array<T>
,而不是 std::is_same_v < T, char[N] >
。
要从您的任何类型中获得 const char*
,您可以使用 std::string_view(t).data()
而不是自己处理每个案例。
由于类型衰减,这是不可能的; T 的结果类型(来自函数 foo)是 char*。你可以通过我的例子弄明白,试着编译它:
#include <type_traits>
template<typename T>
struct is_inbuild_array final : std::false_type{};
template<typename T, std::size_t N>
struct is_inbuild_array<T[N]> final : std::true_type{};
template<typename T>
void f(T val)
{
static_assert(
is_inbuild_array<T>::value,
"Unsupported type"
);
}
int main()
{
char array [] = "Test";
f(array);
}
但是你可以像这样修改你的函数(使用通用参考):
template<typename T>
void f(T&& val)
{
static_assert(
is_inbuild_array<std::remove_reference_t<T>>::value,
"Unsupported type"
);
}
而且效果很好
我最终这样做是为了根据此处的其他答案实施检测:
#include <type_traits>
template < typename Desired, typename Actual > struct is_bounded_type_array : std::false_type {};
template < typename Desired, typename Actual, std::size_t N >
struct is_bounded_type_array < Desired, Actual[N] > : std::conditional_t < std::is_same_v < Actual, Desired >, std::true_type, std::false_type > {};
template < typename Desired, typename Actual >
inline constexpr bool is_bounded_type_array_v = is_bounded_type_array < Desired, Actual > ::value;
然后我可以在我的函数中像这样使用它:
template<typename T>
void test(const T& value)
{
std::cout << is_bounded_type_array_v<char, T> << std::endl;
// or
static_assert(is_bounded_type_array_v<char, T>, "Must be bounded array of type char");
}