2012-11-28 70 views
12

Mã này ...C++ 11 placeholders với tăng

int main() 
{ 
    using namespace std::placeholders; 
    ClassA a; 
    ClassB b, b2; 
    a.SigA.connect(std::bind(&ClassB::PrintFoo, &b)); 
    a.SigB.connect(std::bind(&ClassB::PrintInt, b, _1)); 
    a.SigB.connect(std::bind(&ClassB::PrintInt, &b2, _1)); 

    a.SigA(); 
    a.SigB(4); 
} 

Cung cấp cho các lỗi biên dịch, "lỗi: tham chiếu đến '_1' là mơ hồ"

Nó có thể được cố định bằng cách tuyển đầy đủ placeholders ...

int main() 
{ 
    // using namespace std::placeholders; 
    ClassA a; 
    ClassB b, b2; 
    a.SigA.connect(std::bind(&ClassB::PrintFoo, &b)); 
    a.SigB.connect(std::bind(&ClassB::PrintInt, b, std::placeholders::_1)); 
    a.SigB.connect(std::bind(&ClassB::PrintInt, &b2, std::placeholders::_1)); 

    a.SigA(); 
    a.SigB(4); 
} 

... nhưng tại sao đoạn mã đầu tiên không hoạt động?

EDIT

Chỉ cần để ngăn chặn bất kỳ sự mơ hồ, tôi đang biên soạn với Clang và Tăng 1,52 với --stdlib=libc++ -std=c++0x và toàn bộ khối mã là thế này ...

#include <boost/signals2.hpp> 
#include <iostream> 

struct ClassA 
{ 
    boost::signals2::signal<void()> SigA; 
    boost::signals2::signal<void (int)> SigB; 
}; 

struct ClassB 
{ 
    void PrintFoo()  { std::cout << "Foo" << std::endl; } 
    void PrintInt(int i) { std::cout << "Bar: " << i << std::endl; } 
}; 

int main() 
{ 
    // using namespace std::placeholders; 
    ClassA a; 
    ClassB b, b2; 
    a.SigA.connect(std::bind(&ClassB::PrintFoo, &b)); 
    a.SigB.connect(std::bind(&ClassB::PrintInt, b, std::placeholders::_1)); 
    a.SigB.connect(std::bind(&ClassB::PrintInt, &b2, std::placeholders::_1)); 

    a.SigA(); 
    a.SigB(4); 
} 
+0

gì ... trình biên dịch bạn đang sử dụng? Chỉnh sửa: đừng bận tâm, 'clang' sử dụng' __1' làm điều không gian tên kỳ lạ của nó. – Xymostech

+1

Nếu có cái gì khác gọi là _1 trong phạm vi, sau đó bạn sẽ nhận được lỗi này. [EDIT] một chút quá muộn! – Slicedpan

Trả lời

36

Hãy xem cách này bao gồm việc:

#include <boost/signals2.hpp> bao gồm #include <boost/signals2/signal.hpp> trong đó bao gồm #include <boost/signals2/slot.hpp> trong đó bao gồm #include <boost/bind.hpp> trong đó bao gồm #include <boost/bind/bind.hpp> trong đó bao gồm include <boost/bind/placeholders.hpp>, trong đó sử dụng static boost::arg<1> _1; * trong không gian tên toàn cầu, vì thế mà sự mơ hồ.

*: Về mặt kỹ thuật, _1 nằm trong không gian tên chưa đặt tên nhưng có thể nhìn thấy do chỉ thị sử dụng.

Một workaround là xác định như sau ở phía trên cùng của tập tin của bạn để <boost/bind/placeholders.hpp> không được bao gồm:

#define BOOST_BIND_NO_PLACEHOLDERS 
+1

Trong tất cả các câu trả lời tuyệt vời, câu trả lời này trực tiếp nhất trả lời câu hỏi, vì vậy + 1/Chấp nhận – learnvst

11

C++ thấy hai định danh toàn cầu được đặt tên _1. Nó không có ý tưởng rằng bạn có nghĩa là std::placeholders::_1 thay vì của Boost _1. Đây là một trong những lý do tại sao thư viện chuẩn đặt chúng trong một không gian tên lồng nhau: để ngăn chặn xung đột tình cờ như thế này.

Nếu bạn cần họ sẽ ngắn hơn, chỉ cần tạo một bí danh namespace đơn giản:

namespace ph = std::placeholders 

Sau đó, nó chỉ là ph::_1.

+0

Đề xuất tốt, +1 – learnvst

4

GCC cung cấp cho các thông tin sau đây liên quan tới lỗi của bạn:

.../include/c++/4.7.0/functional:864:34: \ 
    error: candidates are: const std::_Placeholder<1> std::placeholders::_1 
.../boost/1.49.0/boost/bind/placeholders.hpp:55:15: \ 
    error:     boost::arg<1> {anonymous}::_1 

Các gợi ý cho vấn đề có thể được tìm thấy trong lỗi thứ 2: boost::arg<1> {anonymous}::_1

Nguyên nhân là do trình giữ chỗ tăng cường nằm trong một tên ẩn danh ce trong không gian tên chung.

namespace 
{ 
    boost::arg<1> _1; 
    // etc... 
} // unnamed namespace 

Vì trình giữ chỗ tăng nằm trong không gian tên ẩn danh và bạn đang nhập std::placeholders vào không gian tên chung, giờ đây chúng sẵn có trong phạm vi toàn cầu.

Vì vậy, không có cách nào để trình biên dịch biết bạn đang đề cập đến biểu tượng nào.

Như Nicol đề xuất, hãy sử dụng bí danh không gian tên để tạo tiền tố viết tắt std::placeholders::_1 để giảm số lần nhập.

3

Vì bạn đang sử dụng std::bind Tôi cho rằng bạn có một số hỗ trợ C++ 11. Cũng xem xét phiên bản này (ví dụ: thích lambdas qua std::bind)

int main() 
{ 
    ClassA a; 
    ClassB b, b2; 
    a.SigA.connect([&](){ b.PrintFoo(); }); 
    a.SigB.connect([&](int i){ b.PrintInt(i); }); 
    a.SigB.connect([&](int i){ b2.PrintInt(i); }); 

    a.SigA(); 
    a.SigB(4); 
} 
+0

Tốt. Bind là xấu xí anyway! +1 – learnvst

0

workaround khác để này trong một phạm vi bằng cách sử dụng một biến địa phương:

{ 
    auto& _1 = std::placeholders::_1; 
    auto f = std::bind(&Foo::bar, b, _1); 
    ... 
}