[英]Output operator for class template with variadic template pack
我試圖按如下所示編寫模板類和輸出運算符:
#include <iostream>
namespace N
{
template< typename ...types >
struct X
{
static_assert((sizeof...(types) != 0), "zero length");
X() = default;
X(X const &) = default;
X(X &&) = default;
template< typename ...args >
//explicit // does not matter
X(args &&...) { ; }
int value = 10;
};
template< typename ...types >
std::ostream &
operator << (std::ostream & out, X< types... > const & x)
{
return out << x.value;
}
} // namespace N
int main()
{
using namespace N;
X< float > /*const*/ x; // `const` does not matter
std::cout << x << std::endl;
return 0;
}
但是static_assert
離子提出了:
main.cpp:9:5: error: static_assert failed "zero length"
static_assert((sizeof...(types) != 0), "zero length");
^ ~~~~~~~~~~~~~~~~~~~~~~~
main.cpp:32:23: note: in instantiation of template class 'N::X<>' requested here
std::cout << x << std::endl;
^
1 error generated.
如果在全局namespace
定義了類模板X
和operator <<
重載,則所有內容都是相同的。 我發現, using namespace N;
注釋using namespace N;
將X< float >
替換為N::X< float >
解決此問題。
如何解釋這種行為? 原因是什么?
編輯:
我找到了解決方案:如下對operator <<
重載進行模板參數修改:
template< typename first, typename ...rest >
std::ostream &
operator << (std::ostream & out, X< first, rest... > const & x)
{
return out << x.value;
}
typename ..types
分類的typename ..types
。 此外,由於極端的代碼膨脹會導致后果,因此根本不希望這樣做。
重現問題的簡單方法:
int main()
{
using namespace N;
std::cout << std::endl;
}
在這種情況下,候選函數都是std::ostream
namespace std
中operator<<
所有重載, std::ostream
來自所有成員operator <<的,而namespace N
函數模板operator<<
。
13.3.1 / 7:“如果候選對象是功能模板,則使用模板參數推導來生成候選功能模板專業化”
因此,在開始重載解析之前,必須從std::endl
推斷出X<types...> const&
,這是模板函數的地址。 函數的地址是函數指針類型,將N::X<types...> const&
匹配到指針類型的唯一方法是將types...
推導出為空列表。
(替換當然會失敗,因為沒有從任何函數指針類型到N::X<>
隱式轉換,這會以不可行的方式靜默消除重載,但靜態斷言不在立即上下文中並且是一個硬錯誤)
故事的寓意: 使用指令是邪惡的。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.