如何将函数模板作为模板参数传递?

10
#include <iostream>

template<typename... Args>
void print(Args const&... args)
{
    (std::cout << ... << args);
}

int main()
{
    std::cout << 1 << 2 << 3 << std::endl; // ok
    print(1, 2, 3);                        // ok
    print(1, 2, 3, std::endl);             // error! How to make it work?
}

请参见在线演示

如何将函数模板作为模板参数传递?


如果您执行print(1, 2, 3, std::endl<char, std::char_traits<char>>),代码就可以运行。但是您可能想要一个不需要编写所有额外内容的方法。 - mediocrevegetable1
1
有点棘手...我可能会退而使用 '\n'(而不是 std::endl)。 - Scheff's Cat
就像@Scheff'sCat所说,使用\nprint(1, 2, 3, '\n');,除非你绝对必须刷新流。 - Ted Lyngmo
那不是一个“模板”参数。 - Davis Herring
3个回答

10

当其他通常以流作为参数的io操作符是模板时,您将遇到相同的问题。但是您可以将它们包装在非模板可调用项中:

#include <iostream>

template<typename... Args>
void print(Args const&... args)
{
    (std::cout << ... << args);
}
    
int main()
{
    std::cout << 1 << 2 << 3 << std::endl; // ok
    print(1, 2, 3);                        // ok
    print(1, 2, 3, [](std::ostream& o) -> std::ostream&{ 
               o << std::endl; 
               return o;
    });             // no error!
}

输出:

123
123123

语法相对复杂,因此您可能希望使用一个辅助类型,不过我会留给您来编写它(开玩笑的,我认为这并不容易,但我可能稍后会尝试一下 ;)。经过一段时间的思考,我几乎可以确定只有两种选择:实例化函数(参见其他答案),或将调用包装在lambda中,除非您当然想要为每个单独的io操作符编写一个包装器。


7

以下是一种方式:

print(1, 2, 3, std::endl<char, std::char_traits<char>>);

考虑使用'\n'替代。


2
'\n' 不会清空缓冲区,但 std::endl 会!如果 OP 想要怎么办!还可以看一下:能否获取标准库中定义的函数的地址?因此,将其打包到 lambda 中是更好的方法。 - Const
2
你大多数情况下只需要一个 \n,如果你也想刷新缓冲区,请显式地执行。这就是为什么我说“考虑使用”而不是“你应该”。 - Ayxan Haqverdili
关于获取函数地址,这就是“std::endl”的工作原理。 - Ayxan Haqverdili
不应该取标准库函数(或模板)的地址。 - xskxzr
2
@xskxzr:这并不适用于一元操作符(unary manipulators)。 - Davis Herring

5

大多数标准函数的地址是无法取得的(参见 can-i-take-the-address-of-a-function-defined-in-standard-library)。

幸运的是,io-manipulator 是一个例外(请参见Addressable_functions)。

std::endl 是一个模板函数,因此您需要选择正确的重载。

using print_manip_t = std::ostream& (*) (std::ostream&);

print(1, 2, 3, print_manip_t{std::endl});
print(1, 2, 3, static_cast<print_manip_t>(std::endl));
print(1, 2, 3, static_cast<std::ostream& (*) (std::ostream&)>(std::endl));

否则,你必须指定你想要的那一个。
print(1, 2, 3, std::endl<char, std::char_traits<char>>);

或将其包装起来

print(1, 2, 3, [](std::ostream& o) -> std::ostream&{ return o << std::endl; });

演示


1
此外,一个好的建议是:“我可以获取标准库中定义的函数的地址吗? - Const

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