Ori*_*ent 2 c++ templates operator-overloading variadic-templates c++11
我试着写一个模板类和输出操作符,如下所示:
#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;
}
Run Code Online (Sandbox Code Playgroud)
但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.
Run Code Online (Sandbox Code Playgroud)
如果在全局中定义的类模板X和operator <<重载namespace则全部相同.我发现,评论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;
}
Run Code Online (Sandbox Code Playgroud)
分割typename ..types之类的不nessesarily.而且,由于代码的极度膨胀作为后果,所以根本不可取.
一种简单的方法来重现您的问题:
int main()
{
using namespace N;
std::cout << std::endl;
}
Run Code Online (Sandbox Code Playgroud)
在这种情况下,候选人的功能是所有重载operator<<的namespace std,所有成员的operator <<的距离std::ostream,和你的函数模板operator<<从namespace N.
13.3.1/7:"候选者是一个函数模板,使用模板参数推导生成候选函数模板特化"
因此,在开始重载解析之前,X<types...> const&必须从中推导出std::endl,这是模板函数的地址.函数的地址是函数指针类型,匹配N::X<types...> const&指针类型的唯一方法是推导types...为空列表.
(当然替换失败,因为没有任何函数指针类型的隐式转换N::X<>,这会将过载安静地消除为不可行,但静态断言不是直接上下文并且是一个硬错误)
故事的寓意:使用指令是邪恶的.