std::endl and variadic template

10

代码:

#include <iostream>

void out()
{
}

template<typename T, typename... Args>
void out(T value, Args... args)
{
    std::cout << value;
    out(args...);
}

int main()
{
    out("12345", "  ", 5, "\n"); // OK
    out(std::endl);              // compilation error
    return 0;
}

构建错误:

g++ -O0 -g3 -Wall -c -fmessage-length=0 -std=c++11 -pthread -MMD -MP -MF"main.d" -MT"main.d" -o "main.o" "../main.cpp"
../main.cpp: In function ‘int main()’:
../main.cpp:17:15: error: no matching function for call to ‘out(<unresolved overloaded function type>)’
../main.cpp:17:15: note: candidates are:
../main.cpp:3:6: note: void out()
../main.cpp:3:6: note:   candidate expects 0 arguments, 1 provided
../main.cpp:8:6: note: template<class T, class ... Args> void out(T, Args ...)
../main.cpp:8:6: note:   template argument deduction/substitution failed:
../main.cpp:17:15: note:   couldn't deduce template parameter ‘T’

所以,除了 std::endl 之外,一切都正常。我该如何解决这个问题(除了使用 "\n")?


out(&std::endl<char, std::char_traits<char>>); - David G
1个回答

12

std::endl是一个重载函数(在许多STL实现中是一个模板),编译器不知道该选择哪个函数。

只需将其转换为static_cast<std::ostream&(*)(std::ostream&)>(std::endl)


3
重点实际上是这是一个模板,而不是它被过度载入。 - jogojapan
1
@jogojapan:模板在技术上是“重载生成器”:有与流类一样多的std::endl。无论是通过声明它们(例如对于ostream和wostream)还是通过模板(对于ostream<T,Traits>)来实现,这都是一个实现细节,不会改变选择重载的本质。 - Emilio Garavaglia
对于您的解决方案的有效性来说,这并没有什么区别,但模板实例化和重载解析是两种非常不同的机制。将模板称为重载生成器是具有误导性的。 - jogojapan
1
你描述的方式是错误的,模板会生成一组函数,然后应用重载决议来选择一个函数。这种说法有两个问题:a)在简单的重载决议情况下,可供选择的函数集是预定义的,并且隐式类型转换是编译器用于在给定参数和所选函数之间找到匹配项的唯一机制,而在模板实例化的情况下,可以生成一个新的函数实例以完全适应给定的参数。这在模糊的情况下具有广泛的影响。b)在 - jogojapan
1
如果 std::endl 是一组重载函数,那么库的实现存在一个错误,因为它无法与自定义字符特征(或自定义字符类型)一起使用。 - Cubbi
显示剩余3条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接