2012-01-05 22 views
6

Tôi có một hàm cần liệt kê một trình lặp nhiều lần, nhưng according to MSDN, "Khi bạn tăng bất kỳ bản sao nào của trình lặp đầu vào, không một bản sao nào khác có thể được so sánh, dereferenced hoặc tăng lên một cách an toàn sau đó."Làm thế nào để hạn chế một trình lặp trở thành một trình chuyển tiếp tiến trình?

Vì vậy, để dễ dàng hơn, thay vì tạo một triển khai riêng biệt cho các trình chuyển tiếp không sao chép dữ liệu và liệt kê bản sao, tôi muốn hạn chế phương pháp của mình để chỉ thực hiện chuyển tiếp. .

Ngay bây giờ tôi có một cái gì đó như:

template<typename It, typename TCallback /*signature: bool(value_type)*/> 
bool EnumerateTwice(const It &begin, const It &end, TCallback callback) 
{ 
    for (It it = begin; it != end; ++it) 
     if (!callback(*it)) 
      return false; 
    for (It it = begin; it != end; ++it) 
     if (!callback(*it)) 
      return false; 
    return true; 
} 

nhưng không hạn chế It để trở thành một iterator về phía trước.

Làm cách nào để đặt hạn chế đó vào chức năng được tạo khuôn mẫu? (C++ 03)

Trả lời

5

Bạn có thể sử dụng và thay thế SFINAE bool bởi:

typename enable_if< 
    is_same<typename std::iterator_traits<It>::iterator_category, 
      std::forward_iterator_tag>::value, 
    bool>::type 

Bạn có thể cần phải xác định is_sameenable_if mình nếu bạn không muốn kéo chúng từ Boost hoặc TR1:

template <typename A, typename B> 
struct is_same { static const bool value = false; }; 

template <typename T> 
struct is_same<T, T> { static const bool value = true; }; 

template <bool, typename> struct enable_if { }; 
template <typename T> struct enable_if<true, T> { typedef T type; }; 
+0

+1 Oooooo không biết trình lặp được gắn thẻ! Đó là khá tiện dụng. Cảm ơn rất nhiều! :) – Mehrdad

+9

Điều này sẽ từ chối các trình vòng lặp truy cập hai chiều và truy cập ngẫu nhiên. Sử dụng 'is_base_of' thay vì' is_same' cho ngữ nghĩa phù hợp. – ildjarn

+0

@ildjarn: Ồ đúng rồi, điểm tốt; cảm ơn! – Mehrdad

4

Không thử nghiệm nhưng bạn có thể thử một cái gì đó dọc theo dòng:

template<typename It, typename TCallback /*signature: bool(value_type)*/> 
bool EnumerateTwice_Interal(const It &begin, const It &end, TCallback callback, 
     std::forward_iterator_tag) 
{ 
    //do your things 
} 

template<typename It, typename TCallback /*signature: bool(value_type)*/> 
bool EnumerateTwice(const It &begin, const It &end, TCallback callback) 
{ 
    EnumerateTwice_Internal(begin, end, callback, 
     typename std::iterator_traits<It>::iterator_category()); 
} 
+1

+1 để tránh SFINAE - đây là IMO rõ ràng hơn. – ildjarn

3

Bạn có thể làm điều này bằng std::enable_if:

#include <iterator> 
#include <type_traits> 
#include <utility> 

template <typename It, typename TCallback> 
typename std::enable_if<std::is_base_of<std::forward_iterator_tag, 
         typename std::iterator_traits<It>::iterator_category>::value, 
        bool>::type 
EnumerateTwice(It begin, It end, TCallback) { 
    ... 
} 

này sử dụng lớp từ C++ 11 nhưng tất cả điều này có thể được thực hiện trong C++ 03 là tốt.

0

Để mở rộng về câu trả lời của Rodrigo - Tôi tìm thấy giải pháp này, và nghĩ rằng nó là đáng nói:

struct True { unsigned char _[2]; operator bool() const { return true; } }; 
char is_forward_iterator(std::input_iterator_tag const *) { return 0; } 
True is_forward_iterator(std::forward_iterator_tag const *) { return True(); } 

Bây giờ, nếu bạn muốn kiểm tra xem nó bên trong một số chức năng, bạn có thể nói:

if (is_forward_iterator(static_cast<iterator_traits<It>::iterator_category*>(0))) 
{ 
    ... 
} 

và nếu bạn muốn kiểm tra xem nó trong mẫu, bạn có thể kiểm tra:

sizeof(
    is_forward_iterator(static_cast<iterator_traits<It>::iterator_category*>(0)) 
) > 1 

với chính lợi thế của phương pháp này là tránh được việc khai báo mẫu (ví dụ: để có tốc độ biên dịch tốt hơn).

Các vấn đề liên quan