2012-10-28 60 views
10

假設意外超負荷下面的代碼:當函數從可變參數模板實例稱爲叫

#include <iostream> 

template<typename... T> 
void foo(const T &...); 

template<unsigned N> 
void foo(const char (&)[N]) 
{ 
    std::cout << "char(&)[N]" << std::endl; 
} 

void foo(const char *) 
{ 
    std::cout << "const char *" << std::endl; 
} 

template<typename T> 
void foo(const T &) 
{ 
    std::cout << "Single" << std::endl; 
} 

template<typename First, typename... T> 
void foo(const First & first, const T &... rest) 
{ 
    std::cout << "Generic + " << sizeof...(T) << std::endl; 
    foo(first); 
    foo(rest...); 
} 

int main() 
{ 
    const char * c = "asdf"; 
    char a[] = {'a', 'b', 'c', 'd'}; 
    foo('f', c, a, 1); 
    foo(a); 
} 

The output is:

Generic + 3 
Single    // fine; 'f' is `char` -> generic 
Generic + 2 
const char *  // fine; c is `const char *` 
Generic + 1 
const char *  // (!) not fine 
Single 
char(&)[N]   // fine; a is char[4] 

的最後一個電話 - foo(a),其中achar[4] - 調用我的版本期待 - template<unsigned N> void foo(const char (&)[N])。但爲什麼的可變參數模板的實例化不會調用foo(const char (&)[N],而是調用foo(const char *)而不是?如果沒有char數組超載,那應該是預期的 - 但爲什麼它發生在這裏? const First &不應該正確捕獲數組類型?

另外,什麼是最簡單的方法來使通用可變參數版本與傳遞給它的數組正常工作?


由於馬修M.在評論中發現的問題可能不是由可變參數模板引起的,而是由indirection

#include <iostream> 

template <unsigned N> 
void foo(const char (&)[N]) 
{ 
    std::cout << "char(&)[N]" << std::endl; 
} 

void foo(const char *) 
{ 
    std::cout << "const char *" << std::endl; 
} 

template <typename T> 
void goo(T const& t) { 
    foo(t); 
} 

int main() 
{ 
    char a[] = {'a', 'b', 'c', 'd'}; 
    foo(a); 
    goo(a); 
} 
 
    char(&)[N] 
    const char * 

他還表示,這可能是編譯器錯誤 - 雖然代碼在Clang 3.2 dev,G ++ 4.6和4.7中產生完全相同的結果。

R. Martinho費爾南德斯另外,在最後段以const char a[]改變a的類型使得代碼收率const char *兩次。

+1

爲什麼//罰款; 「afas」是const char *'?不是這樣! http://ideone.com/4KewDe –

+0

@ R.MartinhoFernandes,已修復。 – Griwes

+2

我設法進一步減少問題[這裏](http://liveworkspace.org/code/72b3963b4f0c2d00592b4ce00f08fc82)。顯然,這種間接性導致了這個問題,而且可變參數與此無關。仍然沒有找到一個可能的解釋,雖然...它看起來像一個編譯器bug。 –

回答

5

我想我可以回答第二部分:如何解決它?我不確定我是否得到了正確的答案,因爲在我看來,傳遞字符串字面的情況仍然會導致錯誤的結果。修復的基本思路是使用完美的轉發,而不是希望推導出T const&的正確類型。爲什麼使用T const&與數組會導致數組衰減,但我還沒有完全想到。

使用完全向前,當然,意味着該函數做是一個完美的匹配和一些專業化的做一些實際的轉換,至少,加入const。因此,有必要使用不同的名稱。總的來說,這看起來像這樣:

#include <iostream> 
#include <utility> 

void foo() 
{ 
} 

template<unsigned N> 
void special(const char (&)[N]) 
{ 
    std::cout << "char(&)[" << N << "]" << '\n'; 
} 

void special(const char *) 
{ 
    std::cout << "const char *" << '\n'; 
} 

template<typename T> 
void special(const T &) 
{ 
    std::cout << "Single" << '\n'; 
} 

template<typename First, typename... T> 
void foo(First&& first, T&&... rest) 
{ 
    std::cout << "Generic + " << sizeof...(T) << '\n'; 
    special(std::forward<First>(first)); 
    foo(std::forward<T>(rest)...); 
} 

int main() 
{ 
    char const* c("foo"); 
    char a[] = {'a', 'b', 'c', 'd'}; 
    foo('f', "afas", a, c, 1); 
    foo(a); 
}