如何在编译期间计算数组大小(不接受指针)
How compute array size during compilation (without accepting pointers)?
给定一个数组a
,我希望countof(a)
将数组中的元素数量作为编译时常数。如果我有一个指针p
,我希望countof(p)
不编译。这似乎应该是(1)简单明了,(2)通常在SO中涵盖,但(1)我无法让它工作,(2,搜索SO没有找到任何结果。
这是我的尝试。
#include <cstddef>
#include <type_traits>
template<typename T, std::size_t n,
typename = typename std::enable_if<std::is_array<T>::value>::type>
constexpr std::size_t countof(T (&)[n]) { return n; }
template<typename T,
typename = typename std::enable_if<std::is_pointer<T>::value>::type>
void countof(T*) = delete;
int main()
{
int a[10];
auto asize = countof(a); // should compile
static_assert(countof(a) == 10,
"countof(a) != 10!");
int *p;
auto psize = countof(p); // shouldn't compile
}
帮助?
template<typename T, std::size_t N>
constexpr std::size_t countof( T const(&)[N] ) { return N; }
通过两项测试。无法将int*
转换为T const(&)[N]
,因此不需要禁用代码。
为了扩展它,我们应该添加:
template<typename T, std::size_t N>
constexpr std::size_t countof( std::array<T,N> const& ) { return N; }
我甚至可能想将其扩展为对容器调用size()
。虽然通常不会是编译时,但统一性可能很有用:
for(int i=0; i<countof(c); ++i) {
// code
}
或者你有什么。
template<typename T, std::size_t N>
constexpr std::size_t countof( T const(&)[N] ) { return N; }
template<typename T> struct type_sink { typedef void type; };
template<typename T> using TypeSink = typename type_sink<T>::type;
template<typename T, typename=void>
struct has_size : std::false_type {};
template<typename T>
struct has_size<T, TypeSink< decltype( std::declval<T>().size() ) > >:
std::true_type
{};
template<bool b, typename T=void>
using EnableIf = typename std::enable_if<b,T>::type;
template<typename T>
constexpr
EnableIf<has_size<T const&>::value,std::size_t>
countof( T const& t ) {
return t.size();
}
// This is optional. It returns `void`, because there
// is no need to pretend it returns `std::size_t`:
template<typename T>
constexpr
EnableIf<std::is_pointer<T>::value>
countof( T const& t ) = delete;
这非常详细,但为我们提供了std::array
支持、std::initializer_list
支持、C样式数组支持——所有这些都在编译时——以及在运行时标准容器和字符串都可以使用countof
。如果你传递一个指针,你会被告知你调用的函数是delete
ed.
在这种情况下,我试图创建一个static_assert
,但遇到了任何template
都必须具有有效专门化的解析规则的问题。我怀疑通过基于SFINAE的专门化将整个问题路由到countof_impl
类中可能会解决这个问题。
=delete
或static_assert
解决方案的缺点是指针实际上存在过载。如果你没有,那么就没有一个有效的函数可以调用,它需要一个指针:这更接近事实。
像这样:
template <typename T, std::size_t n>
constexpr std::size_t countof(T (&)[n]) { return n; }
template <typename T, typename = typename std::enable_if<std::is_pointer<T>::value>::type>
constexpr std::size_t countof(T) = delete;
您可以这样做:
#include <iostream>
#include <type_traits>
namespace Detail {
template <typename T>
struct array_size {
// A simple false is no good
static_assert(std::is_array<T>::value, "No Array");
};
template <typename T, std::size_t N>
struct array_size<T[N]> {
static constexpr std::size_t value = N;
};
}
template <typename T>
constexpr std::size_t array_size() {
return Detail::array_size<T>::value;
}
template <typename T>
constexpr std::size_t array_size(const T&) {
return Detail::array_size<T>::value;
}
int main(){
typedef int A[3];
typedef char B[array_size<A>()];
A a;
std::cout << array_size<A>() << array_size(a) << array_size<B>() << std::endl;
// int* p = a;
// error: static assertion failed: No Array
// std::cout << array_size(p) << std::endl;
return 0;
}
如果你需要压平所有维度,这个摘录可以在手上
//Moving to detail like 'Dieter Lücking'
namespace detail {
/*recurse over ranks*/
template <typename A, size_t R = std::rank<A>::value>
struct aux {
static constexpr size_t value =
std::extent<A, 0>::value * aux<typename std::remove_extent<A>::type>::value;
};
/*stop condition*/
template <typename A>
struct aux<A, 0> {
static constexpr size_t value = 1;
};
}
/*convenient function, updated to use enable_if, is_array*/
template <typename A, typename = typename std::enable_if<std::is_array<A>::value>::type>
constexpr size_t countof(A const &) {
return detail::aux<A>::value;
}
使用示例:
int a[][3][3] = {
{{1,2,3},
{1,2,3},
{1,2,3}},
{{1,2,3},
{1,2,3},
{1,2,3}}
};
int b[countof(a)]; //size 2*3*3*1 = 18
对于那些必须在没有C++11的constexpr
的情况下使用遗留C++编译器的人来说,以下方法将起作用:
#include <cstddef>
template <class T, size_t N> char (*countof(T(&)[N]))[N]; // declaration only
#define countof(x) sizeof(*countof(x))
int main()
{
int a[10];
size_t asize = countof(a); // should compile
static_assert(countof(a) == 10,
"countof(a) != 10!");
int *p;
size_t psize = countof(p); // shouldn't compile
}
该技术通过在sizeof
运算符中嵌入ADL来确保countof
的编译时评估。
相关文章:
- 为什么线程不接受此输入?
- 函数不接受 X 参数,函数使用默认参数
- C++ boost::asio::ip::tcp::acceptor 有时不接受连接器?
- 如何在不使用指针的情况下将派生类的对象作为参数传递给基类中的函数?
- 在函数中返回无符号字符数组,但不返回指针
- B不接受8作为输入的是什么?C++
- C++数组输入不接受一定数量的整数
- C++概念assignable_from不接受 const&-return 运算符=
- 斯堪夫不接受输入
- C++字符数组不接受超过 4 个字符的输入
- 为什么下面的代码段返回指针指向的值而不是指针的地址?
- 为什么 strtok_r() 只接受字符数组而不接受字符指针
- 为什么 std::string 不接受空指针?
- FLTK 回调不接受我的函数指针
- 为什么 std:map 不能接受指针作为键值?
- 方法指针映射,编译器说他们不接受任何参数
- Ostream操作员Strangley不接受我的堆栈指针
- 如何在编译期间计算数组大小(不接受指针)
- SWIG不接受指针参数的包装对象
- 带有函数指针的模板类不接受专用化