2012-04-25 27 views
6

Tôi đang sử dụng luabind 0.9.1 từ phân phối chính của Ryan Pavlik với Lua 5.1, cygwin trên Win XP SP3 + vá mới nhất x86, tăng 1,48, gcc 4.3.4. Lua và boost là các phiên bản được biên dịch trước của Cygwin.luabind: không thể truy xuất giá trị từ bảng được lập chỉ mục bởi các lớp không có sẵn

Tôi đã xây dựng thành công luabind trong cả phiên bản tĩnh và được chia sẻ.

Cả hai phiên bản đều vượt qua tất cả các bài kiểm tra EXCEPT cho bài kiểm tra test_object_identity.cpp thất bại trong cả hai phiên bản.

Tôi đã theo dõi sự cố sau: Nếu mục nhập trong bảng được tạo cho lớp không được tạo sẵn (tức là, không phải int, chuỗi, v.v.), giá trị KHÔNG THỂ được truy xuất.

Dưới đây là một mảnh mã đó chứng tỏ điều này:

#include "test.hpp" 
#include <luabind/luabind.hpp> 
#include <luabind/detail/debug.hpp> 

using namespace luabind; 

struct test_param 
{ 
    int obj; 
}; 

void test_main(lua_State* L) 
{ 
    using namespace luabind; 

    module(L) 
    [ 
     class_<test_param>("test_param") 
      .def_readwrite("obj", &test_param::obj) 
    ]; 

    test_param temp_object; 
    object tabc = newtable(L); 
    tabc[1] = 10; 
    tabc[temp_object] = 30; 

    TEST_CHECK(tabc[1] == 10);    // passes 
    TEST_CHECK(tabc[temp_object] == 30); // FAILS!!! 

} 

tabc [1] thực sự là 10 trong khi tabc [temp_object] là KHÔNG 30! (thực tế, nó có vẻ là số không)

Tuy nhiên, nếu tôi sử dụng lặp lại để xem các mục nhập tabc, có hai mục nhập với cặp khóa/giá trị ĐÚNG.

Bất kỳ ý tưởng nào?

BTW, quá tải toán tử == như thế này:

#include <luabind/operator.hpp> 

struct test_param 
{ 
    int obj; 
    bool operator==(test_param const& rhs) const 
    { 
     return obj == rhs.obj; 
    } 
}; 

module(L) 
    [ 
     class_<test_param>("test_param") 
      .def_readwrite("obj", &test_param::obj) 
      .def(const_self == const_self) 
    ]; 

Không thay đổi kết quả.

Tôi cũng đã thử chuyển sang phương thức settable() và gettable() từ toán tử []. Kết quả là như nhau. Tôi có thể thấy với trình gỡ rối rằng chuyển đổi mặc định của khóa được gọi, vì vậy tôi đoán lỗi phát sinh từ một nơi nào đó trong đó, nhưng nó vượt ra ngoài tôi để tìm ra chính xác vấn đề là gì.

Như trường hợp thử nghiệm đơn giản cho thấy sau, chắc chắn là một lỗi trong chuyển đổi Luabind của với nhiều loại phức tạp:

struct test_param : wrap_base 
{ 
    int obj; 
    bool operator==(test_param const& rhs) const 
    { return obj == rhs.obj ; } 
}; 

void test_main(lua_State* L) 
{ 
    using namespace luabind; 
    module(L) 
    [ 
     class_<test_param>("test_param") 
       .def(constructor<>()) 
       .def_readwrite("obj", &test_param::obj) 
       .def(const_self == const_self) 
    ]; 

    object tabc, zzk, zzv; 
    test_param tp, tp1; 
    tp.obj = 123456; 
    // create new table 
    tabc = newtable(L); 
    // set tabc[tp] = 5; 
    //   o  k v 
    settable(tabc, tp, 5); 
    // get access to entry through iterator() API 
    iterator zzi(tabc); 
    // get the key object 
    zzk = zzi.key(); 
    // read back the value through gettable() API 
    //    o  k 
    zzv = gettable(tabc, zzk); 
    // check the entry has the same value 
    // irrespective of access method 
    TEST_CHECK (*zzi == 5 && 
       object_cast<int>(zzv) == 5); 
    // convert key to its REAL type (test_param) 
    tp1 = object_cast<test_param>(zzk); 
    // check two keys are the same 
    TEST_CHECK(tp == tp1); 
    // read the value back from table using REAL key type 
    zzv = gettable(tabc, tp1); 
    // check the value 
    TEST_CHECK(object_cast<int>(zzv) == 5); 
    // the previous call FAILS with 
    // Terminated with exception: "unable to make cast" 
    // this is because gettable() doesn't return 
    // a TRUE value, but nil instead 
} 

Hy vọng rằng, một người thông minh hơn tôi có thể con số này ra, Thx

tôi đã truy tìm vấn đề với thực tế là Luabind tạo ra một đối tượng DISTINCT MỚI MỌI thời gian bạn sử dụng một giá trị phức tạp làm khóa (nhưng nó KHÔNG nếu bạn sử dụng một nguyên thủy hoặc một đối tượng).

Dưới đây là một trường hợp thử nghiệm nhỏ mà chứng tỏ điều này:

struct test_param : wrap_base 
{ 
    int obj; 
    bool operator==(test_param const& rhs) const 
    { return obj == rhs.obj ; } 
}; 

void test_main(lua_State* L) 
{ 
    using namespace luabind; 

    module(L) 
    [ 
     class_<test_param>("test_param") 
      .def(constructor<>()) 
      .def_readwrite("obj", &test_param::obj) 
      .def(const_self == const_self) 
    ]; 

    object tabc, zzk, zzv; 
    test_param tp; 
    tp.obj = 123456; 
    tabc = newtable(L); 
    //   o  k v 
    settable(tabc, tp, 5); 
    iterator zzi(tabc), end; 
    std::cerr << "value = " << *zzi << "\n"; 
    zzk = zzi.key(); 
    //   o  k v 
    settable(tabc, tp, 6); 
    settable(tabc, zzk, 7); 
    for (zzi = iterator(tabc); zzi != end; ++zzi) 
    { 
     std::cerr << "value = " << *zzi << "\n"; 
    } 
} 

Chú ý cách tabc [tp] đầu tiên có giá trị 5 và sau đó được ghi đè bằng 7 khi truy cập thông qua các đối tượng chủ chốt. Tuy nhiên, khi truy cập AGAIN thông qua tp, một mục mới sẽ được tạo. Đây là lý do tại sao gettable() thất bại sau đó.

Thx, David

+0

bạn đã từng giải quyết vấn đề này chưa? Tôi đã gặp sự cố này khi sử dụng giá trị int làm khóa cho các bảng, ví dụ: local testTable = {[10] = "màu xanh lá cây", [9] = "màu cam", [8] = "màu vàng"} - nếu tôi sử dụng chuỗi thay vì các số làm khóa - nó hoạt động tốt - tôi cung cấp bảng này làm thông số đến một hàm C++ và tôi cũng nhận được lỗi truyền – Steve

Trả lời

0

Disclaimer: Tôi không phải là một chuyên gia về luabind. Nó hoàn toàn có thể tôi đã bỏ lỡ một cái gì đó về khả năng của luabind.

Trước hết, luabind đang làm gì khi chuyển đổi test_param thành khóa Lua? Chính sách mặc định là bản sao. Để trích dẫn tài liệu luabind:

Điều này sẽ tạo một bản sao của thông số. Đây là hành vi mặc định khi truyền tham số theo giá trị. Lưu ý rằng điều này chỉ có thể được sử dụng khi chuyển từ C++ sang Lua. Chính sách này yêu cầu loại tham số có một hàm tạo bản sao có thể truy cập.

Trong ý nghĩa, điều này có nghĩa là luabind sẽ tạo đối tượng mới (được gọi là "đầy đủ userdata") thuộc sở hữu của bộ gom rác Lua và sẽ sao chép cấu trúc của bạn vào đó. Đây là một điều rất an toàn để làm vì nó không còn quan trọng những gì bạn làm với đối tượng C++; Lua đối tượng sẽ dính xung quanh mà không thực sự bất kỳ chi phí. Đây là cách tốt để thực hiện các ràng buộc cho các loại đối tượng theo giá trị.

Tại sao luabind tạo đối tượng mới mỗi lần bạn chuyển nó cho Lua? Vâng, những gì khác nó có thể làm gì? Nó không quan trọng nếu địa chỉ của đối tượng được truyền là như nhau, bởi vì đối tượng gốc C++ có thể đã thay đổi hoặc bị phá hủy kể từ khi nó được truyền cho Lua. Vì vậy, chỉ với ==, luabind sẽ phải duy trì một danh sách của tất cả các đối tượng của loại đó đã từng được chuyển đến Lua (có thể yếu) và so sánh của bạn đối tượng với từng người để xem liệu nó có phù hợp hay không. luabind không làm điều này (tôi cũng không nên nghĩ).

Bây giờ, hãy nhìn vào phía Lua. Mặc dù luabind tạo ra hai đối tượng khác nhau, chúng vẫn bằng nhau, phải không? Vâng, vấn đề đầu tiên là, bên cạnh một số loại built-in, Lua chỉ có thể giữ các đối tượng bằng cách tham chiếu. Mỗi "đầy đủ userdata" mà tôi đã đề cập trước đây thực sự là một con trỏ. Điều đó có nghĩa là chúng không giống nhau.

Nhưng chúng bằng nhau, nếu chúng tôi xác định một hoạt động meta __eq. Thật không may, Lua chính nó chỉ đơn giản là không hỗ trợ trường hợp này. Userdata khi được sử dụng làm khóa bảng luôn được so sánh với danh tính, bất kể là gì. Điều này thực sự không đặc biệt cho userdata; nó cũng đúng với các bảng. (Lưu ý rằng để hỗ trợ đúng trường hợp này, Lua sẽ cần ghi đè lên hoạt động hashcode trên đối tượng ngoài __eq. Lua cũng không hỗ trợ ghi đè hoạt động hashcode.) Tôi không thể nói cho các tác giả của Lua tại sao họ không cho phép điều này (và nó đã được đề xuất trước đó), nhưng có nó.

Vì vậy, các tùy chọn là gì?

  • Điều đơn giản nhất là chuyển đổi test_param thành đối tượng một lần (rõ ràng) và sau đó sử dụng đối tượng đó để lập chỉ mục bảng cả hai lần. Tuy nhiên, tôi nghi ngờ rằng trong khi điều này sửa chữa ví dụ đồ chơi của bạn, nó không phải là rất hữu ích trong thực tế.
  • Một tùy chọn khác đơn giản là không sử dụng các loại như khóa. Trên thực tế, tôi nghĩ rằng đây là một gợi ý rất tốt, vì loại liên kết trọng lượng nhẹ này khá hữu ích, và lựa chọn duy nhất khác là loại bỏ nó.
  • Có vẻ như bạn có thể xác định chuyển đổi tùy chỉnh trên loại của mình. Trong ví dụ của bạn, nó có thể là hợp lý để chuyển đổi loại của bạn thành một số Lua mà sẽ cư xử tốt như một chỉ số bảng.
  • Sử dụng loại ràng buộc khác. Sẽ có một số chi phí, nhưng nếu bạn muốn nhận dạng, bạn sẽ phải sống với nó. Có vẻ như luabind có một số hỗ trợ cho trình bao bọc, mà bạn có thể cần phải sử dụng để giữ lại danh tính:

    Khi một con trỏ hoặc tham chiếu đến một lớp đã đăng ký với trình bao bọc được chuyển đến Lua, luabind sẽ truy vấn loại động . Nếu loại động thừa hưởng từ wrap_base, thì nhận dạng đối tượng được giữ nguyên.

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