2017-07-19 153 views
1

在下面的代碼中,我有一個名爲data的變量。它內部包含一個函數來稍後調用它們。假設data在另一個庫中定義,我無法更改其類型。我爲其中每個已知函數的一部分(s3)的成員分配模板函數,並且在調用函數時必須給出一部分函數(true)。我能不能通過這樣的事情:如何用已知的函數參數來避免lambda函數?

data[0]=test_func(?,s3); // error 

相反,我要傳遞一個lambda函數給它:

data[0]=[](bool b){test_func(b,s3);}; // ok 

但lambda函數看起來並不整齊尤其是當我們有100數組這些任務。有沒有辦法通過以任何方式更改test_func來避免lambda函數?即使使用test_func內的lambda也對我來說是可以的,因爲它只寫了一次。

#include <iostream> 
#include <functional> 

template<typename F> 
void test_func(bool b,F f) 
{ 
    if(b) 
     f(); 
} 

void s1() 
{ 
    std::cout<<"s1 \n"; 
} 

void s2() 
{ 
    std::cout<<"s2 \n"; 
} 

void s3() 
{ 
    std::cout<<"s3 \n"; 
} 

int main() 
{ 
    test_func(true,s1); 
    test_func(true,s2); 
    test_func(false,s1); 
    test_func(true,s2); 
    ///////////////// 
    std::function<void(bool)> data[100]; 
    // data=test_func(?,s3); // error 
    data[0]=[](bool b){test_func(b,s3);}; // ok 
    data[0](true); 
    return 0; 
} 
+0

這不只是'的std ::函數 foo(F f){return [](bool b){test_func(b,f); }; }'? – melpomene

+0

現在,最好的解決方案是簡單地使用lambda函數。 'std :: bind'試圖做到這一點,但使用它需要學習它的迷你語言(對於任何讀取代碼的人),並且往往會使編譯器難以優化。此外,它最終只比lambda函數短。 – Justin

+0

@melpomene,你如何適應這個代碼? – ar2015

回答

2

如果你想避免lambda功能完全,以及templates你可以使用的功能(類operator()):

typedef void (&F)(void); 
class TestFunc { 
    F f; 
    public: 
    TestFunc(const F f) : f(f) {} 
    void operator()(bool B) const { 
     if(B) f(); 
    } 
}; 

TestFunc(s3)分配它。只是typedefF向功能型,不需要模板:

typedef void (&F)(void); 

,並徹底清除模板 - 我通常喜歡少模板如果可能的話,但是這味道。如果您需要不同的功能簽名支持,則只會真正調用模板。

要使用標準庫功能只是改變typedef

typedef std::function<void(void)> F; 
+0

'template '? '錯誤:ISO C++禁止聲明'功能'沒有類型' – ar2015

+0

非常感謝。這個解決方案可以擴展到'std :: function'嗎? – ar2015

+0

我添加了一些'const'正確性,如果它很重要。 – kabanus

1

你可以創建一個輔助函數的拉姆達:

#include <iostream> 
#include <string> 
#include <functional> 
#include <vector> 

template<typename F> 
void test_func(bool b,F f) { 
    if(b) { 
     f(); 
    } 
} 

std::function<void(bool)> wrap_function(const std::function<void(void)> &f) { 
    return [f](bool b){test_func(b,f);}; 
} 

void s1() { 
    std::cout<<"s1 \n"; 
} 

int main() { 
    std::vector<std::function<void(bool)>> data; 

    data.push_back(wrap_function(s1)); 

    data[0](true); 
} 

而且你應該使用std::vectorstd::array或其他性病的容器而不是std::function<void(bool)> data[100]

2

如果每個s_n是一個常規函數具有相同的簽名,您可以從test_func中刪除f參數,而是將該函數本身作爲模板參數傳遞。

template<void(&f)()> 
void test_func(bool b) 
{ 
    if(b) 
     f(); 
} 

而且使用這樣的:

data[0] = test_func<s1>; 

函數指針和引用明確允許作爲模板非類型參數由[temp.param/4]

A non-type template-parameter shall have one of the following (optionally cv-qualified) types:

[...]

  • pointer to object or pointer to function,
  • lvalue reference to object or lvalue reference to function,
+0

喜兄弟再次。它可以通過std :: function而不是指針來完成嗎? – ar2015

+0

@ ar2015 - 不可以,因爲對於初學者來說,一個'std :: function'不能是一個常量表達式。它具有允許類型擦除的狀態。從某種意義上說,函數指針只能在編譯時「固定」,因此纔是允許的。 – StoryTeller

+0

這是否意味着指針在優化方面優於'std :: function'? – ar2015