VS2013 上的模板专业化和 SFINAE

Template specialization and SFINAE on VS2013

我正在使用 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 以外的其他类型来实现此功能,并且效果很好。此外,我知道 ostream 没有复制构造函数这一事实,起初我怀疑这是这里的问题。

但是,我尝试在 main 中的调用点显式指定模板参数:

mwrite<std::string, std::ostream&>(std::string("Hello"), out, err);

这也很好用。因此,我发现自己处于编译器在特定专业化(具有按值传递 ostreams 的专业化)上失败的情况,而确实存在一个完全合法的专业化(具有按引用传递 ostreams)。我不愿意责怪编译器,所以我的问题是:这种行为是否仍然符合 SFINAE 标准?我是不是误会了什么?

这与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...); }
//                                       ^