2014-04-29 125 views
2

我試着寫一個模板類和輸出運算符將其如下:與可變參數模板包類模板輸出操作

#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. 

如果類模板X和全局namespace中定義的operator <<重載全部相同。我發現,評論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不nessesarily。而且,由於代碼的嚴重膨脹而導致後果並不理想。

+0

使用''\ n''而不是多餘的'std :: endl'修復了它。 – Cubbi

回答

5

一種簡單的方式來重現您的問題:

int main() 
{ 
    using namespace N; 
    std::cout << std::endl; 
} 

在這種情況下,候選人的功能是從namespace stdoperator<<所有重載,所有成員運營商< <的從std::ostream,並從namespace N你的函數模板operator<<

13.3.1/7:

所以,在重載決議可以開始,X<types...> const&必須從std::endl推斷「如果候選人是一個函數模板,使用模板參數推導產生候選函數模板特」,這是一個模板函數的地址。函數的地址是函數指針類型,將N::X<types...> const&與指針類型匹配的唯一方法是將types...推導爲空列表。因爲不存在從任何函數指針類型到N::X<>的隱式轉換,這將會消除靜態過載,因爲不可行,但靜態斷言不在緊接上下文中並且是硬錯誤)

故事的寓意:使用指令是邪惡的。

+0

很好的解釋。但是推斷'types ...'爲空列表還不夠清楚。 – Orient

+0

如何將'N :: X < types... > const&'視爲'decltype(std :: endl)'類型的指針? – Orient

+1

在這個答案中,將'template struct X'替換爲'template struct X'應該解決這個問題。 – Orient