9

arrayを指定すると、配列内の要素の数をコンパイル時の定数として生成し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
}

ヘルプ?

4

5 に答える 5

8
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できます。ポインターを渡すと、呼び出した関数がdeleteed であることが通知されます。

その場合にを作成しようとしましたが、有効な特殊化が必要static_assertであるという解決ルールで問題が発生しました。template問題全体countof_implを SFINAE ベースの特殊化を持つクラスにルーティングすると、その問題が解決するのではないかと思います。

=deleteorソリューションの欠点は、static_assert実際にはポインターのオーバーロードが存在することです。それがない場合は、ポインターを受け取る有効な関数を呼び出すことはできません。これは真実に近いです。

于 2014-01-18T17:37:57.037 に答える
3

このような:

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;
于 2014-01-18T17:52:22.073 に答える
1

あなたはこれを行うかもしれません:

#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;
}
于 2014-01-18T17:53:01.187 に答える
1

C++11なしで従来の C++ コンパイラを使用する必要がある私たちにとってはconstexpr、次のように動作します。

#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
}

この手法では、演算子countof内に ADL を埋め込むことにより、コンパイル時の評価が保証されます。sizeof

于 2014-05-27T04:21:41.803 に答える