2011-08-03 79 views
2

我被困在專業的模板功能拉姆達:模板專門用於傳遞拉姆達

class X 
{ 
    public: 
    template <typename T> 
    void f(T t) 
    { 
     std::cout << "awesome" << std::endl; 
    }; 

    template <> 
    void f(double t) 
    { 
     std::cout << "trouble" << std::endl; // Works 
    } 

    template <> 
    void f(??? t) // what to put here? 
    { 
     std::cout << "lambda" << std::endl; 
    } 
}; 


X x; 
x.f(42); // prints "awesome" 
x.f(1.12); // prints "trouble" 
x.f([](){ std::cout << "my lazy lambda" << std::endl; }); // should print "lambda" 

傳遞給F和專門爲這種類型的作品前,鑄造拉姆達爲std ::功能,但單調乏味的寫作。 C++ 0x中有解決方案嗎?

編輯:我對解決方案完全沒問題,如果傳遞lambda表達式的最後一行可以使我專門爲可調用的方法。

+0

相關:http://stackoverflow.com/questions/4731947 /超載-ON-stdfunction – stijn

+1

因此,答案似乎是:沒有,是C++ 0x中沒有辦法避免的演員和專業的模板匹配lambda表達式。 –

+2

如之前討論過(http://stackoverflow.com/questions/4661875/is-ac-is-lambda-trait-purely-implemented-as-a-library-impossible),這是不可能從其他區分lambda函數可調用對象 –

回答

1

你不能直接這樣做:lambda的類型是由編譯器創建的,每個lambda都不同。你可以專注於它,但它只適用於這種類型(見下面的例子)。你可以通過使用一個小函數來轉換lambda - > std :: function來消除一些繁瑣的問題。

auto myLambda = [](){ std::cout << "myLambda" << std::endl; }; 

class X 
{ 
    public: 
    template <typename T> 
    void f(T t) 
    { 
     std::cout << "not so awesome" << std::endl; 
    }; 

    void f(const std::function< void() >& f) 
    { 
     std::cout << "function" << std::endl; 
    } 

    void f(const decltype(myLambda)& f) 
    { 
     std::cout << "myLambda" << std::endl; 
    } 
}; 

    //helper for lambda -> function 
template< class T > 
std::function< void() > Function(const T& f) 
{ 
    return std::function< void() >(f); 
} 

X x; 
x.f(myLambda); //prints "myLambda" 
x.f(Function([](){ std::cout << "blah" << std::endl; })); //prints "function" 
x.f([](){ std::cout << "blah" << std::endl; }); //still won't work: not the same type as myLambda! 
+0

最後一行永遠不會匹配lambda,因爲每個lambda具有不同的唯一類型 –

4

以下是好老的sizeof把戲的變化。也許可以單獨使用decltype來完成。它並不完全檢查它是否是lambda,但是如果它是可調用的。如果您想篩選出其他可調用的東西,你可以使用的C++ 0x型性狀檢查它們是否函數,成員函數,組合大對象等

#include <functional> 
#include <iostream> 
#include <type_traits> 

template<class T> 
char is_callable(const T& t, decltype(t())* = 0); 

long is_callable(...); 

class X 
{ 
    public: 
    template <typename T> 
    void f(const T& t, typename std::enable_if<sizeof(is_callable(t)) !=1>::type* = 0) 
    { 
     std::cout << "awesome" << std::endl; 
    }; 

    void f(double) 
    { 
     std::cout << "trouble" << std::endl; // Works 
    } 

    template<class T> 
    void f(const T& t, typename std::enable_if<sizeof(is_callable(t)) == 1>::type* = 0) 
    { 
     std::cout << "lambda" << std::endl; 
    } 
}; 

int main(int argc, const char *argv[]) 
{ 
    X x; 
    x.f(42); // prints "awesome" 
    x.f(1.12); // prints "trouble" 
    x.f([](){ std::cout << "my lazy lambda" << std::endl; }); // should print "lambda" 
} 
+2

這不會專門用於lambdas,只有可調用類型 - 不是相同的東西。 – Puppy

+0

而這可能是最好的一個可以做的,也許只有改變SFINAE來測試確切的簽名,並非所有可調用類型 –

+0

@DeadMG:我與任何匹配可調用,只要我能避免在最後投完全罰款。 –