2012-11-28 55 views
12

此代碼...C++ 11個佔位符與升壓

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); 
} 

給人的編譯錯誤,「錯誤:參照‘_1’不明確」

它可以通過完全限定被固定佔位符...

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); 
} 

...但爲什麼第一個代碼片段不起作用?

編輯

只是爲了防止任何含糊之處,我與鏘編譯並與--stdlib=libc++ -std=c++0x升壓1.52和整個代碼塊是這樣的......

#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

什麼...編譯您使用的?編輯:沒關係,'clang'使用'__1'作爲它奇怪的命名空間的東西。 – Xymostech

+1

如果在範圍內有其他名稱爲_1的其他內容,則會出現此錯誤。 [編輯]有點晚了! – Slicedpan

回答

36

讓我們來看看如何在包括工作:

#include <boost/signals2.hpp>包括#include <boost/signals2/signal.hpp> 包括#include <boost/signals2/slot.hpp>包括#include <boost/bind.hpp>包括#include <boost/bind/bind.hpp>,其中包括include <boost/bind/placeholders.hpp>,它採用static boost::arg<1> _1; *在全局命名空間,因此不確定性。

*:從技術上講,_1位於未命名的名稱空間中,但由於using指令而可見。

一種解決方法是定義在你的文件的頂部以下,這樣<boost/bind/placeholders.hpp>不包括:

#define BOOST_BIND_NO_PLACEHOLDERS 
+1

在所有的好的答案中,這一個最直接地回答問題,所以+ 1 /接受 – learnvst

11

C++看到兩個命名全局標識符_1。它不知道你的意思是std::placeholders::_1而不是Boost的_1。這是標準庫將它們放入嵌套名稱空間的原因之一:防止這樣的意外衝突。

如果你需要他們更短,只需要創建一個簡單的命名空間別名:

namespace ph = std::placeholders 

然後,它只是ph::_1

+0

好的建議,+1 – learnvst

4

GCC給出關於你的錯誤的以下信息:

.../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 

的暗示,問題可以在第二個錯誤中找到:boost::arg<1> {anonymous}::_1

原因是增強佔位符處於匿名namespa在全局命名空間內。

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

由於升壓佔位符是一個匿名的命名空間,要導入std::placeholders到全局命名空間,他們現在在全球範圍內都可用。

因此,編譯器無法知道您所指的是哪個符號。

正如Nicol所示,使用命名空間別名來創建一個簡寫前綴std::placeholders::_1以減少鍵入。

3

由於您使用的是std::bind我想你有一些C++ 11的支持。想想也是這個版本通過使用一個局部變量(即更喜歡std::bind lambda表達式)

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

尼斯。無論如何,綁定是醜陋的! +1 – learnvst

0

另一個解決方法,以這樣的範圍內:

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