VS2013上的模板专业化和SFINAE

时间:2015-02-25 12:42:20

标签: c++ c++11 visual-studio-2013 variadic-templates

我正在使用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?我在这里误解了什么吗?

1 个答案:

答案 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...); }
//                                       ^