我正在使用VS2013(更新4),而且我在编译以下可变参数模板代码时遇到问题:
#include <iostream>
#include <string>
// Variadic template "multiwrite" for writing a string to multiple different streams
template <typename T>
void mwrite(T value, std::ostream& os) { os << value; }
template <typename T, typename... SS>
void mwrite(T value, std::ostream& os, SS... streams) { mwrite(value, os); mwrite(value, streams...); }
// Main
int main()
{
std::ostream& out = std::cout;
std::ostream& err = std::cerr;
mwrite(std::string("Hello"), out, err);
return 0;
}
我得到的编译错误是:
error C2280: 'std::basic_ostream<char,std::char_traits<char>>::basic_ostream(const std::basic_ostream<char,std::char_traits<char>> &)' : attempting to reference a deleted function
see declaration of 'std::basic_ostream<char,std::char_traits<char>>::basic_ostream'
我尝试使用除std :: ostreams之外的其他类型实现此函数,这些工作正常。另外,我知道ostreams没有复制构造函数的事实,起初我怀疑这是问题所在。
然而,我尝试在main中的调用点显式指定模板参数:
mwrite<std::string, std::ostream&>(std::string("Hello"), out, err);
这也很好。因此,我发现自己的情况是编译器在特定的特化(具有按值传递ostreams的特殊化)上失败,而确实存在完全合法的特化(具有传递引用的ostreams)。我不愿责怪编译器,所以我的问题是:这种行为是不是仍然符合SFINAE?我在这里误解了什么吗?
答案 0 :(得分:3)
这与SFINAE无关。无论如何,这里没有替代失败。 SFINAE与模板参数替换有关,创建了一个格式错误的函数声明。签名void mwrite(std::string, std::ostream&, std::ostream);
没有任何不良形式。
问题是您按值传递SS
,因此最终尝试制作流的副本。流不可复制。通过引用传递:
template <typename T, typename... SS>
void mwrite(T value, std::ostream& os, SS&... streams) { mwrite(value, os); mwrite(value, streams...); }
// ^