2010-10-29 26 views
18

Nói chung, tôi sẽ sử dụng boost::mpl::for_each<>() phải đi qua một boost::mpl::vector, nhưng điều này đòi hỏi một functor với một mẫu chức năng tuyên bố như sau:Có thể lặp lại một vector mpl :: tại thời gian chạy mà không tạo ra các loại trong vectơ không?

template<typename T> void operator()(T&){T::staticCall();}

Vấn đề của tôi với điều này là tôi không muốn đối tượng T được khởi tạo bởi for_each<>. Tôi không cần tham số T ở số operator(). Có cách nào để thực hiện điều này, hoặc thay thế cho for_each<> mà không vượt qua một đối tượng kiểu T đến hàm mẫu?

cách tối ưu, tôi muốn các nhà điều hành() định nghĩa để trông như thế này:

template<typename T> void operator()(){T::staticCall();}

Và tất nhiên, tôi không muốn T được khởi tạo ở tất cả trước khi cuộc gọi. Bất kỳ lời khuyên/gợi ý khác cũng được chào đón.

Trả lời

13

Câu hỏi thú vị! Theo như tôi có thể nói, Boost.MPL dường như không cung cấp một thuật toán như vậy. Tuy nhiên, viết của riêng bạn không nên quá khó khăn bằng cách sử dụng vòng lặp.

Đây là một giải pháp khả thi:

#include <boost/mpl/begin_end.hpp> 
#include <boost/mpl/next_prior.hpp> 
#include <boost/mpl/vector.hpp> 

using namespace boost::mpl; 


namespace detail { 

template < typename Begin, typename End, typename F > 
struct static_for_each 
{ 
    static void call() 
    { 
     typedef typename Begin::type currentType; 

     F::template call<currentType>(); 
     static_for_each< typename next<Begin>::type, End, F >::call(); 
    } 
}; 


template < typename End, typename F > 
struct static_for_each< End, End, F > 
{ 
    static void call() 
    { 
    } 
}; 

} // namespace detail 


template < typename Sequence, typename F > 
void static_for_each() 
{ 
    typedef typename begin<Sequence>::type begin; 
    typedef typename end<Sequence>::type end; 

    detail::static_for_each< begin, end, F >::call(); 
} 

[Việc đặt tên có thể không được lựa chọn rất tốt, nhưng cũng ...]

Đây là cách bạn sẽ sử dụng thuật toán này:

struct Foo 
{ 
    static void staticMemberFunction() 
    { 
     std::cout << "Foo"; 
    } 
}; 


struct Bar 
{ 
    static void staticMemberFunction() 
    { 
     std::cout << "Bar"; 
    } 
}; 


struct CallStaticMemberFunction 
{ 
    template < typename T > 
    static void call() 
    { 
     T::staticMemberFunction(); 
    } 
}; 


int main() 
{ 
    typedef vector< Foo, Bar > sequence; 

    static_for_each< sequence, CallStaticMemberFunction >(); // prints "FooBar" 
} 
+0

Hướng dẫn rất hữu ích tại đây. Cảm ơn. – Marcin

1

Trước tiên, lệnh gọi tĩnh trong mã của bạn có nghĩa là đối tượng của bạn sẽ tồn tại. Trước/sau là vô nghĩa trong vấn đề đó. Lần duy nhất, "Tôi không muốn T được khởi tạo trước khi gọi," ý nghĩa là khi T là một mẫu. Nó không phải, bởi vì nó không thể được. Đúng là dòng đó làm cho đối tượng tồn tại, nhưng tôi khá chắc chắn rằng nó sẽ không chỉ tồn tại ở đó khi sản phẩm được biên dịch.

Thứ hai, tôi không tin rằng có một phương pháp hiện tại để sử dụng for_each mà không cần instantiating. IMHO đây là một lỗi trong MPL gây ra bởi một quyết định có vấn đề để sử dụng toán tử(). Sẽ không nói nó sai vì tôi biết nhà phát triển và anh ấy thông minh hơn tôi nhiều, nhưng có vẻ như từ bây giờ bạn đã mang nó lên.

Vì vậy, tôi nghĩ rằng bạn đang bị mắc kẹt phải làm lại một for_each gọi một hàm templated không yêu cầu tham số. Tôi gần như chắc chắn nó là có thể, nhưng cũng bằng nhau chắc chắn nó không phải là dễ dàng có sẵn như là một thành phần premade trong MPL.

1

Marcin, bạn rất đúng. Tôi đã suy nghĩ điều này và tôi không thấy một giải pháp dễ dàng cho việc này. Thậm chí nếu bạn không thể viết số trống operator(), thì ít nhất cũng có thể sử dụng một con trỏ, điều đó không cần một đối tượng thực sự tồn tại. Bạn phải cuộn thực hiện của riêng bạn, có vẻ như.

+0

Tôi nghĩ rằng không có giải pháp "dễ dàng" vì giải pháp _easy_ đã có: sử dụng 'mpl :: begin' và' mpl :: end'. Về cơ bản bạn cần phải đi qua nó cho mình. Cũng giống như bạn phải viết rất dài 'cho (std :: vector :: iterator it = v.begin() ...' điều cho vòng lặp. Bạn có thể viết hàm bậc cao hơn để đơn giản hóa nó nhưng cuối cùng bạn vẫn cần phải đi qua nó như @Luc Touraille gợi ý – kizzx2

14

Chỉ gặp phải tình huống tương tự và cung cấp giải pháp khác cho vấn đề mà tôi muốn chia sẻ. Nó không phải là hiển nhiên, nhưng nó sử dụng một thuật toán hiện có. Ý tưởng là sử dụng con trỏ để thay thế.

typedef boost::mpl::vector<type1*, type2*> container; 

struct functor 
{ 
    template<typename T> void operator()(T*) 
    { 
     std::cout << "created " << typeid(T).name() << std::endl; 
    } 
}; 

int main() 
{ 
    boost::mpl::for_each<container>(functor()); 
} 

vì vậy ở đây chúng tôi nhận được một con trỏ rỗng, nhưng chúng tôi không quan tâm vì chúng tôi sẽ không sử dụng chúng.

Như tôi đã nói trước đó không rõ ràng trong mã và có thể sẽ yêu cầu một số nhận xét bổ sung, nhưng nó vẫn giải quyết được câu hỏi mà không cần viết bất kỳ mã bổ sung nào.

thêm

Tôi nghĩ Diego Sevilla đề nghị một cái gì đó tương tự.

+4

Điều này khá thông minh Bạn có thể sử dụng 'mpl :: transform' để xác định phiên bản" con trỏ "khi đang bay:' boost :: mpl :: for_each > :: type> (Functor()); ' – kizzx2

+4

@ kizzx2 Bạn thậm chí có thể không cung cấp con trỏ mà là một kiểu trống có chứa kiểu. – Klaim

1

Đây là giải pháp thay thế được lấy cảm hứng từ Luc Touraille's answer.

Phiên bản này được thực hiện bằng cách sử dụng Metafunction classes thay vì chức năng cho phép static_for_each được gọi ngay cả bên ngoài phạm vi chức năng (hữu ích nếu công việc phải hoàn toàn được thực hiện tại compiletime).

Ngoài ra, nó còn mang lại nhiều tương tác hơn nhờ các typaief firstlast, cho phép lấy thông tin ra khỏi vòng lặp nếu cần, giống như cách return hoạt động cho một chức năng.

Bạn cũng có thể truy cập kết quả lặp lại trước đó trong mỗi lần lặp lại nhờ tham số mẫu thứ hai Previous được chuyển đến lớp metafunction F.

Cuối cùng, bạn có thể cung cấp dữ liệu cho quy trình vòng lặp sử dụng tham số mẫu Initial, nó sẽ được cung cấp dưới dạng giá trị của tham số Previous của lần lặp đầu tiên.

# include <boost/mpl/begin_end.hpp> 
# include <boost/mpl/next_prior.hpp> 
# include <boost/mpl/apply.hpp> 

namespace detail_static_for_each 
{ 
    // Loop 
    template<typename Begin, typename End, typename F, typename Previous> 
    struct static_for_each 
    { 
    private: 
    typedef typename Begin::type        current_type; 

    public: 
    typedef typename boost::mpl::apply<F, current_type, Previous>::type    first; 
    typedef typename static_for_each<typename boost::mpl::next<Begin>::type, End, F, first>::last last; 
    }; 

    // End of loop 
    template<typename End, typename F, typename Last> 
    struct static_for_each<End, End, F, Last> 
    { 
    public: 
    typedef Last first; 
    typedef Last last; 
    }; 

} // namespace detail_static_for_each 

// Public interface 
template<typename Sequence, typename F, typename Initial = void> 
struct static_for_each 
{ 
private: 
    typedef typename boost::mpl::begin<Sequence>::type  begin; 
    typedef typename boost::mpl::end<Sequence>::type   end; 

    typedef typename detail_static_for_each::static_for_each<begin, end, F, Initial> loop; 

public: 
    typedef typename loop::first     first; 
    typedef typename loop::last     last; 
}; 

Dưới đây là một ví dụ đơn giản mà cả cho và lấy dữ liệu:

# include <iostream> 

# include <boost/type_traits/is_same.hpp> 

# include <boost/mpl/if.hpp> 
# include <boost/mpl/vector.hpp> 

# include "static_for_each.hpp" 

struct is_there_a_float                                                
{                                                      
    template<typename currentItem, typename PreviousIterationType>                                      
    struct apply                                                  
    {                                                     
     typedef typename boost::mpl::if_< PreviousIterationType,                                       
              PreviousIterationType,                                       
              boost::is_same<float, currentItem> >::type type;                               
    };                                                     
}; 

struct test                                                   
{                                                      
    typedef boost::mpl::vector< char, long, long, double, float, int, char > sequence;                                 

    typedef static_for_each<sequence, is_there_a_float, boost::false_type>::last found;                            
}; 

int  main(void)                                                 
{                                                      
    std::cout << std::boolalpha << test::found::value << std::endl;                                      

    return (0);                                                   
} 

Những tính năng này làm cho việc sử dụng các static_for_each hơn tương tự như việc sử dụng các vòng thi chung (while, for, BOOST_FOREACH .. .) khi bạn có thể tương tác trực tiếp hơn với vòng lặp.

+0

như tôi có thể nói, bạn chỉ cần triển khai lại [mpl :: fold] (http://www.boost.org/doc/libs/release/libs/mpl/doc/refmanual/fold.html). của 'mpl :: for_each' là nó hoạt động trong thời gian chạy (tốt, lặp lại được thực hiện tại thời gian biên dịch, nhưng nó gọi các hoạt động thời gian chạy), và tôi giả định OP muốn hành vi này.Nếu không, anh ta sẽ có u sed một trong nhiều thuật toán biên dịch thời gian được cung cấp bởi MPL. –

+0

@LucTouraille Tôi đồng ý với bạn.Câu trả lời này được coi là thông tin tiền thưởng hơn là một câu trả lời trực tiếp. – Drax

0

Tôi thích (lên bình chọn) giải pháp với con trỏ và chức năng * _for_each được xác định riêng. Đây là một thay thế bằng cách sử dụng loại wrapper cho T nếu mục tiêu là để tránh tạo đối tượng cho đến khi nó là cần thiết.

template<typename T> 
struct Wrapper 
{ 
    typedef T type; 
}; 

struct Functor 
{ 
    template<typename T> void operator()(T t) 
    { 
    T::type obj(1); 
    T::type::static_fuc(); 
    } 
}; 

struct T1 
{ 
    T1(int a) : m_a(a) { } 
    int m_a; 
    static inline void static_fuc() { } 
}; 
struct T2 
{ 
    T2(int a) : m_a(a) { } 
    int m_a; 
    static inline void static_fuc() { } 
}; 

void fun() 
{ 
    namespace mpl=boost::mpl; 
    typedef mpl::vector<Wrapper<T1>,Wrapper<T2> > t_vec; 
    mpl::for_each<t_vec>(Functor()); 
} 
Các vấn đề liên quan