2012-09-28 118 views
9

我正在嘗試使用ANSI C++ for_each語句來遍歷並打印標準向量的元素。它有效,如果我有for_each調用一個非重載函數,但如果我有它調用一個重載函數會產生編譯器錯誤。g ++編譯器錯誤:無法推導出模板參數'_Funct'

這裏有一個最小的測試程序,以顯示其中發生編譯器錯誤:

#include <algorithm> 
#include <iostream> 
#include <vector> 

struct S { 
    char c; 
    int i; 
}; 
std::vector<S> v; 

void print_struct(int idx); 
void print_struct(const struct S& s); 

// f: a non-overloaded version of the preceding function. 
void f(const struct S& s); 

int main() 
{ 
    v.push_back((struct S){'a', 1}); 
    v.push_back((struct S){'b', 2}); 
    v.push_back((struct S){'c', 3}); 

    for (unsigned int i = 0; i < v.size(); ++i) 
     print_struct(i); 

    /* ERROR! */ 
    std::for_each(v.begin(), v.end(), print_struct); 

    /* WORKAROUND: */ 
    std::for_each(v.begin(), v.end(), f); 

    return 0; 
} 

// print_struct: Print a struct by its index in vector v. 
void print_struct(int idx) 
{ 
    std::cout << v[idx].c << ',' << v[idx].i << '\n'; 
} 

// print_struct: Print a struct by reference. 
void print_struct(const struct S& s) 
{ 
    std::cout << s.c << ',' << s.i << '\n'; 
} 

// f: a non-overloaded version of the preceding function. 
void f(const struct S& s) 
{ 
    std::cout << s.c << ',' << s.i << '\n'; 
} 

我的openSUSE 12.2編譯這個使用:

g++-4.7 -ansi -Wall for_each.cpp -o for_each 

完整的錯誤信息是:

for_each.cpp: In function ‘int main()’: 
for_each.cpp:31:48: error: no matching function for call to ‘for_each(std::vector<S>::iterator, std::vector<S>::iterator, <unresolved overloaded function type>)’ 
for_each.cpp:31:48: note: candidate is: 
In file included from /usr/include/c++/4.7/algorithm:63:0, 
       from for_each.cpp:5: 
/usr/include/c++/4.7/bits/stl_algo.h:4436:5: note: template<class _IIter, class _Funct> _Funct std::for_each(_IIter, _IIter, _Funct) 
/usr/include/c++/4.7/bits/stl_algo.h:4436:5: note: template argument deduction/substitution failed: 
for_each.cpp:31:48: note: couldn't deduce template parameter ‘_Funct’ 

我在堆棧溢出或網絡ge上看不到此特定錯誤的任何搜索結果nerally。任何幫助,將不勝感激。

+0

http://ideone.com/nqL3x – BoBTFish

回答

6

名稱是指重載集。你需要指定超載你想要的:

std::for_each(v.begin(), v.end(), (void (&)(S const&)) print_struct); 

另一種方法是使用多態可調用的函數對象作爲幫助:

struct PrintStruct 
{ 
    template <typename T> void operator()(T const& v) const 
     { return print_struct(v); } 
}; 

int main() 
{ 
    PrintStruct helper; 

    std::vector<S> sv; 
    std::vector<int> iv; 

    // helper works for both: 
    std::for_each(sv.begin(), sv.end(), helper); 
    std::for_each(iv.begin(), iv.end(), helper); 
+0

感謝您提供快速,清晰,功能正確的響應。它確實解決了錯誤。 –

+0

@Matt:就這樣,如果任何一個答案解決了你的問題,請*接受*答案。您可以通過點擊答案旁邊的勾號勾選。 :)如果多個答案解決了你的問題,那就選擇一個。 – Xeo

4

std::for_each聲明如下所示:

template<class InputIter, class Func> 
void for_each(InputIter first, InputIter last, Func func); 

正如你所看到的,它需要任何東西你給它作爲第三個參數。沒有限制,它必須是某個簽名或可調用類型的可調用類型

當處理重載函數時,它們本質上是不明確的,除非您給它們一些上下文來選擇正確的函數。在對重載函數的調用中,此上下文是您傳遞的參數。但是,如果需要指針,則不能將參數用作上下文,並且參數也不會被視爲上下文,因爲它需要任何內容​​。

作爲其中一個函數參數可以是一個有效的上下文選擇合適的超載爲例,看看這個:

// our overloads 
void f(int){} 
void f(double){} 

typedef void (*funcptr_type)(int); 
void g(funcptr_type){} 

// ... 
g(&f); // will select 'void f(int)' overload, since that's 
     // the only valid one given 'g's parameter 

正如你所看到的,你給一個清晰的脈絡在這裏,可以幫助編譯器選擇正確的過載並沒有模棱兩可。 std::for_each的參數做不是給出了這樣的背景,因爲他們採取任何東西。

有兩個解決方案:

  • 手動提供的上下文或者通過
    • 鑄造到正確的函數指針類型,或
    • 使用正確類型的中間變量,並且通過該
  • 使用非重載函數調度到超載函數(如您使用f

注意,在C++ 11,你也可以使用第二個選項拉姆達:

std::for_each(v.begin(), v.end(), [](const S& s){ print_struct(s); }); 

的一些注意事項您的代碼:

  • (struct S){'a', 1}是一個複合文字而不是標準C++
  • 你不需要在C++中使用struct S,只有S夠用
+0

那裏有很多很好的背景。我的代碼的筆記也讚賞。我想知道爲什麼複合文字通過g ++ - 4.7的錯誤檢查。我確實使用了-ansi標誌。 –

+0

@user:使用'-pedantic','-ansi'暗示C99 IIRC,而GCC默認支持C++。 – Xeo