これがばかげた考えであることは承知していますが、コンテナー タイプと非コンテナー タイプの両方に単一のクラスを使用できるかどうかを確認したかったのです。まず、この質問からコードをコピーして貼り付けました。
次に、2 つのヘルパー関数があります。1 つはメンバー関数T
変数の型 ( memberがあるかどうかvalue_type
) を決定するためのもので、もう 1 つは の戻り値を決定するためのものですoperator *
。
template <typename T>
typename std::enable_if<HasValueType<T>::value, typename T::value_type>::type
proxy_func_op() {
}
template <typename T>
typename std::enable_if<!HasValueType<T>::value, T>::type
proxy_func_op() {
}
template <typename T>
typename std::enable_if<HasValueType<T>::value, typename T::const_iterator>::type
proxy_func_mem() {
}
template <typename T>
typename std::enable_if<!HasValueType<T>::value, T*>::type
proxy_func_mem() {
}
そして、私のクラスは次のようになります。
template<typename T>
class MyIterator {
cur
メンバーがない場合はT
、代わりにへのポインターにする必要があります。この場合、begin と end は使用されません。const_iterator
T
value_type
decltype(proxy_func_mem<T>()) begin;
decltype(proxy_func_mem<T>()) end;
decltype(proxy_func_mem<T>()) cur;
public:
これが私の init 関数のロジックです。
template <typename U = T>
typename std::enable_if<HasValueType<U>::value, void>::type
init(U t) {
static_assert(std::is_same<typename T::const_iterator,
decltype(proxy_func_mem<U>())>::value,
"Make sure correct function is called.");
begin = t.begin();
end = t.end();
cur = begin;
}
template <typename U = T>
typename std::enable_if<!HasValueType<U>::value, void>::type
init(U t) {
static_assert(!std::is_same<typename T::const_iterator,
decltype(proxy_func_mem<U>())>::value,
"Make sure correct function is called.");
cur = &t;
}
問題をこの1行に絞り込みました。最初のオーバーロードの内容を直接削除init<T>(t)
してコピー アンド ペーストすると、適切な結果が得られます。そうしないと、間違った結果が得られます。
explicit MyIterator(const T& t) {
init<T>(t);
}
MyIterator& operator++() {
static_assert(HasValueType<T>::value, "You cannot use this operator for non-containers.");
if (cur + 1 != end)
cur++;
return *this;
}
decltype(proxy_func_op<T>()) operator *() {
return *cur;
}
};
たとえば、間違った出力は次のとおりです。
0
0
3
4
5
h
i
正しい関数を呼び出しているようです。何が問題ですか?
編集
何らかの理由で、関数の署名を変更しinit(const U& t) {
て問題を修正します。誰でも理由を説明できますか?
Valgrind エラー:
==4117== Invalid read of size 4
==4117== at 0x401270: MyIterator<std::vector<int, std::allocator<int> > >::operator*() (main.cpp:78)
==4117== by 0x400E8A: main (main.cpp:87)
==4117== Address 0x514d0a0 is 0 bytes inside a block of size 20 free'd
==4117== at 0x4A05FD6: operator delete(void*) (vg_replace_malloc.c:480)
==4117== by 0x401CC5: __gnu_cxx::new_allocator<int>::deallocate(int*, unsigned long) (new_allocator.h:110)
==4117== by 0x401999: std::_Vector_base<int, std::allocator<int> >::_M_deallocate(int*, unsigned long) (stl_vector.h:174)
==4117== by 0x4014A4: std::_Vector_base<int, std::allocator<int> >::~_Vector_base() (stl_vector.h:160)
==4117== by 0x4011A0: std::vector<int, std::allocator<int> >::~vector() (stl_vector.h:416)
==4117== by 0x401209: MyIterator<std::vector<int, std::allocator<int> > >::MyIterator(std::vector<int, std::allocator<int> > const&) (main.cpp:67)
==4117== by 0x400E75: main (main.cpp:85)
を呼び出さない場合、Valgrind はエラーを検出しませんinit<T>(t)
。