如何在编译期间计算数组大小(不接受指针)?

Kno*_*abe 9 c++ arrays templates enable-if c++11

给定一个数组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
}
Run Code Online (Sandbox Code Playgroud)

救命?

Yak*_*ont 8

template<typename T, std::size_t N>
constexpr std::size_t countof( T const(&)[N] ) { return N; }
Run Code Online (Sandbox Code Playgroud)

通过两个测试.无法将int*a 转换为a T const(&)[N],因此不需要禁用代码.

要扩展它,我们应该添加:

template<typename T, std::size_t N>
constexpr std::size_t countof( std::array<T,N> const& ) { return N; }
Run Code Online (Sandbox Code Playgroud)

我甚至可能想把它扩展到调用size()容器.虽然它通常不是编译时,但统一性可能有用:

for(int i=0; i<countof(c); ++i) {
  // code
}
Run Code Online (Sandbox Code Playgroud)

或者你有什么.

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;
Run Code Online (Sandbox Code Playgroud)

这是非常冗长,但给我们std::array支持,std::initializer_list支持,C风格的数组支持 - 所有在编译时 - 并在运行时标准容器和字符串都countof能够.如果您传递指针,则会告诉您所调用的函数是deleteed.

我尝试static_assert在这种情况下创建一个,但遇到了解决规则的问题,任何template必须具有有效的专业化.我怀疑将整个问题路由到countof_impl基于SFINAE的专业化的类可能会解决这个问题.

一个缺点到=deletestatic_assert解决方案是,在过载实际上存在指针.如果你没有那个,那么就没有一个有效的函数可以调用一个指针:这更接近事实.