2013-11-27 17 views
7

Tôi đã cố gắng phát với macro BOOST_FUSION_ADAPT_STRUCT và đã thử một số điều ngây thơ như sử dụng Fusion để in bất kỳ cấu trúc tùy ý nào.Giới hạn của BOOST_FUSION_ADAPT_STRUCT

Bắt đầu từ example code given in the documentation này, tôi không thể thực hiện trên cấu trúc được điều chỉnh của mình một số thao tác được phép có trình tự kết hợp.

#include <boost/fusion/adapted.hpp> 
#include <boost/fusion/sequence/io/out.hpp> 
#include <boost/fusion/sequence/intrinsic.hpp> 
#include <boost/fusion/view.hpp> 
#include <iostream> 

namespace fuz = boost::fusion; 

namespace demo 
{ 
    struct employee 
    { 
     std::string name; 
     int age; 
    }; 
} 

// demo::employee is now a Fusion sequence 
BOOST_FUSION_ADAPT_STRUCT(
    demo::employee, 
    (std::string, name) 
    (int, age)) 

int main() 
{ 
    // tried to initialize an employee like a fusion sequence 
    // but it didnt work 
    // demo::employee e("bob", 42); 

    demo::employee e; 
    e.name = "bob"; 
    e.age = 42; 

    // Access struct members with fusion random access functions 
    // ok 
    std::cout << fuz::at_c<0>(e) << std::endl; 

    // tried to print the struct like any othe fusion sequence 
    // didnt work 
    // std::cout << e << std::endl; 

    // I made it work by using a fusion view 
    // is it the right way? 
    std::cout << fuz::as_nview<0, 1>(e) << std::endl; 
} 

Điều này dẫn tôi đến các câu hỏi sau:

  • Tại sao Magik Fusion không hoạt động ở đây?

  • Sử dụng chế độ xem là cách chính xác để in cấu trúc được điều chỉnh?

  • Cấu trúc thích nghi có thể được sử dụng như một chuỗi Fusion?

Trả lời

8

Từ các tài liệu boost::fusion:

Các I/O khai thác đang bị quá tải trong thúc đẩy namespace :: fusion

Điều đó có nghĩa rằng nếu bạn muốn có một hội nhập tiềm ẩn của những operator<<, bạn sẽ cần phải tiêm không gian tên boost::fusion vào không gian tên hiện tại của mình (:: tại đây) hoặc sử dụng chúng một cách rõ ràng.

Tổng hợp tất cả lên, nói thêm:

using namespace boost::fusion; 

nên làm việc trong trường hợp của bạn. Hoặc cho việc sử dụng rõ ràng, bạn sẽ phải viết:

boost::fusion::operator<<(std::cout, e) << std::endl; 

--- EDIT ---

Sau khi đọc mã boost::fusion 's một chút, nó có vẻ rằng bạn đang bối rối vì Tra cứu của Koenig của boost::fusion::operators::operator<< được chọn trong trường hợp đối số của bạn là boost::fusion::sequence thực.

Đây là lý do tại sao bạn không cần phải tiêm không gian tên boost::fusion, cũng không gọi boost::fusion::operator<< cho các loại được xác định trong không gian tên boost::fusion.

Một số giải thích:

Tôi sẽ không giải thích toàn bộ khái niệm về tra cứu Koenig (còn được gọi là Argument Dependent Lookup - ADL) ở đây vì đó không phải là vấn đề, nhưng về cơ bản, nó khẳng định rằng trong trường hợp bạn đang sử dụng một biến có kiểu nằm bên trong một không gian tên, sau đó tìm kiếm hàm mở rộng đến vùng tên của tham số đó.

Trong trường hợp cụ thể này, bao gồm boost/fusion/sequence/io/out.hpp sẽ xác định boost::fusion::operator::operator<< sau đó sẽ được đưa vào không gian tên boost::fusion.

$ cat /usr/local/include/boost/fusion/sequence/io/out.hpp 
[...] 
namespace boost { namespace fusion 
{ 
    [...] 
    namespace operators 
    { 
     template <typename Sequence> 
     inline typename 
      boost::enable_if< 
       fusion::traits::is_sequence<Sequence> 
       , std::ostream& 
      >::type // this is just a SFINAE trick to ensure 
        // the function will only be selected for 
        // actual boost::fusion::sequence 
     operator<<(std::ostream& os, Sequence const& seq) 
     { 
      return fusion::out(os, seq); // this will print out the sequence 
     } 
    } 
    using operators::operator<<; // here the operator<< is injected 
           // in boost::fusion 
}} 

Điều này có nghĩa rằng các cuộc gọi sử dụngoperator<<với các thông số có loại là trong không gian tênboost::fusionsẽ tìm thấy sự quá tải thích hợp.

Cuộc gọi sử dụng các đối số có loại không nằm trong không gian tên này sẽ không giải quyết được tình trạng quá tải thích hợp của operator<< (đây là trường hợp trong ví dụ của bạn).

Bạn có thể kiểm tra điều đó bằng cách xác định loại của bạn trong không gian tên boost::fusion.

namespace boost { namespace fusion { 
struct employee 
{ 
    std::string name; 
    int age; 
}; 
}} 

BOOST_FUSION_ADAPT_STRUCT(
    boost::fusion::employee, 
    (std::string, name) 
    (int, age)) 

[...] 
boost::fusion::employee e; 
std::cout << e << std::endl; // ADL will work here 

Lưu ý phụ: Nếu bạn muốn gỡ lỗi các vấn đề tra cứu tên, bạn nên sử dụng gdb. Bằng cách đó bạn sẽ luôn biết được tình trạng quá tải nào đã được chọn. Trong trường hợp này:

$ cat fusion.cpp 
#include <iostream> 
#include <cstdlib> 

#include <boost/fusion/container/vector.hpp> 
#include <boost/fusion/sequence/io.hpp> 

int main(int, char**) 
{ 
    boost::fusion::vector<int, char> foo(42, '?'); 
    std::cout << foo << std::endl; 

    return EXIT_SUCCESS; 
} 

$ gdb -q ./fusion 
Reading symbols for shared libraries ... done 
(gdb) b 10 
Breakpoint 1 at 0x1000012f7: file fusion.cpp, line 10. 
(gdb) r 
Starting program: /Users/avallee/Projects/tmp/fusion 
Reading symbols for shared libraries ++............................. done 

Breakpoint 1, main (unnamed_arg=0x7fff5fbffb60, unnamed_arg=0x7fff5fbffb60) at fusion.cpp:10 
10 std::cout << foo << std::endl; 
(gdb) s 
boost::fusion::operators::operator<< <boost::fusion::vector<int, char, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_> > ([email protected], [email protected]) at out.hpp:38 
38    return fusion::out(os, seq); 
4

Cảm ơn rất nhiều Aurelien đã giải thích chi tiết của bạn. Tôi cũng đã tìm thấy this post trên các nhóm trên google. Như giải thích của bạn sẽ dẫn đến, cách đơn giản nhất để làm cho mọi thứ hoạt động được đặt trong không gian tên bản demo:

namespace demo{ 
    using boost::fusion::operators::operator<<; 
    ...