是否有一些技巧可以让我将流操作符传递给可变参数模板函数?

use*_*683 10 c++ templates variadic-templates c++11

我一直在尝试为std :: cout编写一个线程安全的包装器,并认为这是学习一些可变参数模板的好时机.

像那样.

然后,当我认为我做对了,我注意到它与std :: endl不兼容.

拿这个代码:

template <typename... P>
void f(P...){}

int main()
{
    f(1,2,3,std::endl);
}
Run Code Online (Sandbox Code Playgroud)

当你尝试编译它时,GCC以一种非常愚蠢的方式抱怨:

main.cpp:18:19: error: too many arguments to function 'void f(P ...) [with P = {}]'
Run Code Online (Sandbox Code Playgroud)

当您使用常规模板尝试时,您会得到

main.cpp:22:13: error: no matching function for call to 'f(<unresolved overloaded function type>)'
Run Code Online (Sandbox Code Playgroud)

这实际上是有道理的.

这对我来说不是一个大问题,我可以用其他方式来做,但我真的想知道是否有办法绕过这个限制.

Ste*_*vej 14

我没有使用Andy Prowl建议的显式模板参数,而是推荐模板参数推导:

C:\Temp>type meow.cpp
#include <iostream>
#include <utility>
using namespace std;

void Print() { }

template <typename T, typename... Rest> void Print(T&& t, Rest&&... rest) {
    cout << forward<T>(t);
    Print(forward<Rest>(rest)...);
}

int main() {
    ostream& (* const narrow_endl)(ostream&) = endl;

    Print("Hello, world!", narrow_endl, "I have ", 1729, " cute fluffy kittens.",
        static_cast<ostream& (*)(ostream&)>(endl)
    );
}

C:\Temp>cl /EHsc /nologo /W4 /MTd meow.cpp
meow.cpp

C:\Temp>meow
Hello, world!
I have 1729 cute fluffy kittens.
Run Code Online (Sandbox Code Playgroud)

N3690 13.4 [over.over]指定此处使用的规则,这些规则可以追溯到C++ 98.基本上,获取重载和/或模板化函数的地址通常是模糊的,但在特定上下文中是允许的.初始化和static_casting是其中两个上下文,因为它们提供了足够的类型信息来消除歧义.这允许模板参数推断正常进行.

显式模板参数非常诱人,但它们可以以各种方式爆炸.std :: endl不太可能以一种破坏显式模板参数的方式进行更改,但我确实建议不要使用它们(除非专门为它们设计了东西,比如forward和make_shared).


And*_*owl 10

问题在于操纵器就像std::endl是功能模板.因此,您必须明确要传递的函数模板的哪个特化(否则,不能进行类型推导).

例如:

f(1, 2, 3, &std::endl<char, std::char_traits<char>>);
//                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Run Code Online (Sandbox Code Playgroud)