2016-09-13 44 views
2

我試圖設計一個C++宏,必須是這個樣子:如何在lambda變量中使用decltype而不捕獲它?

#define MY_MACRO(OBJECT, METHOD)       \ 
    [](BaseClass* obj)          \ 
    {              \ 
     return static_cast<decltype(OBJECT)>(obj)->METHOD();\ 
    } 

基本上,轉換成調用給定對象上的給定方法的拉姆達的宏。但lambda需要將對象的基類作爲參數(我的用例保證了轉換將始終工作)。此外,要調用的方法可能不在基類上。

該宏的用法是,我有我不能修改聲明爲另一種方法:

void Foo(std::function<int(BaseClass*)>); 

,我需要能夠使用我的宏作爲像這​​樣的參數來調用它:

T x; 
Foo(MY_MACRO(x, method)); // match std::function<int(T*)> 

但是,宏代碼不起作用,因爲我沒有捕獲OBJECT,所以它不在範圍內,當我需要將它傳遞給decltype時。從概念上講,編譯器需要的所有信息都在那裏......我該怎麼做?可能嗎?

一些限制:

  1. 拉姆達的參數需要BaseClass的。我不能讓它decltype(OBJECT)。
  2. 我的情況不允許我捕獲OBJECT。
  3. 我無法訪問通用lambda捕獲的C++ 14功能。
+0

你有沒有考慮過'std :: mem_fn'? –

+0

是的,我已經嘗試過,但我無法在我的情況下使用它。我正在概括我的問題陳述;事實上,這不是那麼簡單。但底線是它需要是一個lambda,我需要訪問對象的類型而不捕獲它。 –

+0

您可以添加一個用法示例,僅用於說明嗎? –

回答

1

您可以將一個可選參數添加到您想要的類型的lambda表中,並在該參數上使用decltype。下面是模式的一個例子,減去宏:

int main() { 
    int foo = 4; 
    auto lambda = [](double* bar, decltype(foo)* TP = nullptr) { 
     return static_cast<std::remove_pointer<decltype(TP)>::type>(*bar); 
    }; 

    double x = 5; 
    return lambda(&x); 
} 

我得到一個指向decltype(foo)這裏,因爲指針類型可以很容易地被默認爲nullptr,確保參數是可選。如果decltype(foo)已經解析爲一個指針類型,就像你的情況,如果我把它正確的話,你就不需要它(和remove_pointer)。

+0

我不能這樣做,可悲的是,因爲我需要宏來計算匹配std :: function 的東西。不要擔心int,我的用例保證類型總是匹配。 –

+0

@PaulAccisano,你可以通過捕獲具有正確簽名的另一個lambda中的lambda來逃脫。 – zneak

+1

@PaulAccisano,不,等等,你甚至不需要那個。 lambda可以直接進入該類型的'std :: function':http://cppshell.com/2uy5x – zneak

1

下面是一個嘗試:

template <typename T> 
auto lambda_maker(int (T::* MF)()) 
{ 
    return [](T* p) -> int { return (p->*MF)(); }; 
} 

#define MY_MACRO(OBJ, METH) lambda_maker<decltype(OBJ)>(METH) 
+0

這可能工作,我會嘗試。 –

3

我需要訪問對象的類型沒有捕捉它。

你可以直接做。只有當您使用命名實體時才需要捕獲數據,而未評估的操作數(如decltype)不會使用任何東西。這是非常好的:

void f(){ 
    int x; 
    []{ decltype(x) y = 0; }; 
} 
+0

有趣的是,這無法在Visual Studio中編譯。編譯器錯誤? –

+2

@PaulAccisano MSVC,是吧? /嘆 –

相關問題