has-an-stl-container-like-interfaceの一般的なコンパイル時テストが
適切な解決策であるという提案を追求して、これはインターフェースによってstlのようなコンテナー T
を定義
します。
T::iterator T::begin();
T::iterator T::end();
T::const_iterator T::begin() const;
T::const_iterator T::end() const;
*T::iterator is T::value_type &
*T::const_iterator is T::value_type const &
メソッドなどの追加要件をsize()
明白な方法で追加することも、コンパイル時に明白な同様の方法でプローブされる他の正規型インターフェースを追加することもできます。
#ifndef IS_STL_CONTAINER_LIKE_H
#define IS_STL_CONTAINER_LIKE_H
#include <type_traits>
template<typename T>
struct is_stl_container_like
{
typedef typename std::remove_const<T>::type test_type;
template<typename A>
static constexpr bool test(
A * pt,
A const * cpt = nullptr,
decltype(pt->begin()) * = nullptr,
decltype(pt->end()) * = nullptr,
decltype(cpt->begin()) * = nullptr,
decltype(cpt->end()) * = nullptr,
typename A::iterator * pi = nullptr,
typename A::const_iterator * pci = nullptr,
typename A::value_type * pv = nullptr) {
typedef typename A::iterator iterator;
typedef typename A::const_iterator const_iterator;
typedef typename A::value_type value_type;
return std::is_same<decltype(pt->begin()),iterator>::value &&
std::is_same<decltype(pt->end()),iterator>::value &&
std::is_same<decltype(cpt->begin()),const_iterator>::value &&
std::is_same<decltype(cpt->end()),const_iterator>::value &&
std::is_same<decltype(**pi),value_type &>::value &&
std::is_same<decltype(**pci),value_type const &>::value;
}
template<typename A>
static constexpr bool test(...) {
return false;
}
static const bool value = test<test_type>(nullptr);
};
#endif
これは、GCC 4.7.2、clang 3.2、Intel C++13.1.1でビルドされたテストプログラムです。
#include "is_stl_container_like.h"
// Testing ...
#include <iostream>
#include <vector>
#include <array>
#include <functional>
using namespace std;
template<class C>
struct polymorphic : private C
{
typedef typename C::value_type value_type;
typedef typename C::iterator iterator;
typedef typename C::const_iterator const_iterator;
virtual ~polymorphic(){}
virtual const_iterator begin() const {
return C::begin();
}
virtual iterator begin() {
return C::begin();
}
virtual const_iterator end() const {
return C::end();
}
virtual iterator end() {
return C::end();
}
};
template<class C>
struct reject : private C
{
typedef typename C::value_type value_type;
typedef typename C::iterator iterator;
typedef typename C::const_iterator const_iterator;
const_iterator begin() {
return C::begin();
}
iterator begin() const {
return C::begin();
}
const_iterator end() {
return C::end();
}
iterator end() const {
return C::end();
}
};
int main()
{
cout << is_stl_container_like<vector<int> const >::value << endl; // Yes
cout << is_stl_container_like<array<int,42>>::value << endl; // Yes
cout << is_stl_container_like<polymorphic<vector<int>>>::value << endl; // Yes
cout << is_stl_container_like<function<int(int)>>::value << endl; // No
cout << is_stl_container_like<int>::value << endl; // No
cout << is_stl_container_like<reject<vector<int>>>::value << endl; //No
}