[英]Variadic templates not compiling in MSVC?
嘗試編譯以下代碼片段:此代碼顯然使用了 C++11 功能,並在 The C++ Programming Language book §3.4.4 中進行了描述
template<typename T>
void g(T x)
{
std::cout << x << " ";
}
template<typename T, typename... Tail>
void f(T head, Tail... tail) {
g(head); // do something to head
f(tail...); // tr y again with tail
}
void f() {}
int main()
{
f(1, "Lol", 5);
getchar();
}
VS17 輸出:
C2672 'f': 沒有找到匹配的重載函數 Line:21
'void f(T,Tail...)':需要 2 個參數 - 0 提供 Line:19
有任何想法嗎 ?
首先是 MCVE:
template<typename T, typename... Tail>
void f(T head, Tail... tail) {
f(tail...); // tr y again with tail
}
f(1, 2, 3);
現在實例化:
f<int, int, int>(1, 2, 3);
編譯為:
template<T = int, Tail...={int,int}>
void f(int head, int tail0, int tail1) {
f(tail0, tail1); // tr y again with tail
}
遞歸調用是:
f<int,int>(tail0, tail1); // tr y again with tail
編譯為:
template<T = int, Tail...={int}>
void f(int head, int tail0) {
f(tail0); // tr y again with tail
}
遞歸調用解析為:
f<int>(tail0); // tr y again with tail
編譯為:
template<T = int, Tail...={}>
void f(int head) {
f(); // tr y again with tail
}
在這里我們嘗試調用f()
。
沒有對f()
有效調用可見,因此您會收到錯誤消息。
調用f()
下的void f() {}
在這里沒有幫助,因為在模板中查找是在f()
可見之前完成的。
如果您想以簡單的方式解決此問題,您可以在f
模板上方添加inline void f(){}
。
更復雜的方法?
template<class...Ts>
void f(Ts...ts) {
using discard=int[];
(void)discard{ 0, ( void(
g(ts)
),0)...};
}
這也消除了遞歸。 或者在c++17 中:
template<class...Ts>
void f(Ts...ts) {
( (void)(g(ts)), ... );
}
這也可以更快地編譯,因為它創建的符號更少(和更短)。
這里有三件事不正確。
tail
參數陰影模板名稱tail
f()
基本情況f()
必須在另一個f(...)
之前定義,因為高級函數查找不會發生在這樣的遞歸函數中。解決方案
將參數tail
的名稱更改為其他名稱
template<typename T, typename... tail>
void f(T head, tail... ftail) { //tail here was shadowing actual template name tail so changed to ftail
g(head); // do something to head
f(ftail...); // try again with tail
}
當您對f()
進行遞歸調用時,有時沒有值傳遞給f(..)
因為每次遞歸調用都會將傳遞的參數數量減少 1。
所以假設你從f(1, "Lol", 2)
,在內部遞歸調用f("Lol", 2)
這反過來調用f(2)
調用f()
,但是你的函數f
需要至少 1 個參數。 因此錯誤
要解決此問題,只需重載基本案例場景的f
,而無需像這樣的參數
void f(){
//last recursive call made
}
這是完整的代碼
#include<iostream>
template<typename T>
void g(T x)
{
std::cout << x << " ";
}
void f(){ }
template<typename T, typename... tail>
void f(T head, tail... ftail) {
g(head); // do something to head
f(ftail...); // try again with tail
}
int main()
{
f(1, "Lol", 5);
getchar();
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.