具有可变参数模板包的类模板的输出运算符
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.
如果类模板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;
}
将类typename ..types
拆分不是必然的。此外,由于代码极度膨胀的后果,这根本不是可取的。
重现问题的简单方法:
int main()
{
using namespace N;
std::cout << std::endl;
}
在这种情况下,候选函数都是来自namespace std
的operator<<
重载,所有成员运算符<<来自std::ostream
,而你的函数模板operator<<
来自namespace N
。
13.3.1/7:"如果候选函数是函数模板,则使用模板参数推导生成候选函数模板专用化">
因此,在开始解决重载之前,必须从std::endl
推导出X<types...> const&
,这是模板函数的地址。函数的地址是函数指针类型,将N::X<types...> const&
与指针类型匹配的唯一方法是将types...
推断为空列表。
(替换当然会失败,因为没有从任何函数指针类型到 N::X<>
的隐式转换,这会悄悄地消除过载,因为不可行,但静态断言不在直接上下文中,是一个硬错误(
这个故事的寓意是:使用指令是邪恶的。
相关文章:
- 尝试重载输出运算符时,我无法遍历对象向量
- 如何为流输出运算符提供重载<<模板'using'类型别名?
- 在C++中重载输入/输出运算符
- 如何处理自定义输出运算符中的 iomanips?
- 基于对函数的参数调用流输出运算符的能力重载函数
- C++将 toString 替换为重载的输出运算符
- 尝试过载输出运算符时出错
- 重载输出运算符给出十六进制数字而不是字符串
- 重载输入/输出运算符,为什么它以这种方式工作而不是以另一种方式工作
- Qt 使用迭代器重载了 qtextstream 输出运算符
- 抽象类和派生类的输出运算符 (<<)
- 重载输出运算符和后置增量运算符时"运算符<<"错误不匹配
- 如何在输出运算符中测试std::showbase或std::noshowbase
- 队列类C++的输出运算符重载
- 变量类型和变量模板的转换和输出运算符
- 重载输出运算符<<以使用 STL 列表迭代器
- C++抽象类的输出运算符
- 重载基类及其派生类(C++)的输出运算符
- 重载输出运算符时出现错误
- 为什么我的输出运算符 <<() 函数定义会导致无法解析的外部符号错误?