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

xml*_*lmx 9 c++ templates overloading overload-resolution c++17

#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?
}
Run Code Online (Sandbox Code Playgroud)

在线演示

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

for*_*818 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!
}
Run Code Online (Sandbox Code Playgroud)

输出

123
123123
Run Code Online (Sandbox Code Playgroud)

语法相当繁重,因此您可能想要使用辅助类型,尽管我将其留给您来编写(只是开玩笑,我认为这不是微不足道的,但我可能会稍后尝试;)。经过一段时间的思考,我几乎可以肯定只有两种选择:实例化函数(参见其他答案),或者将调用包装在 lambda 中,除非您想为每个单个 io 操纵器编写一个包装器课程。


Ayx*_*xan 7

这里有一个方法:

print(1, 2, 3, std::endl<char, std::char_traits<char>>);
Run Code Online (Sandbox Code Playgroud)

考虑'\n'改用。

  • [`'\n'` 不会刷新缓冲区,但 `std::endl` 会!](/sf/ask/14973521/)。如果 OP 想要那个怎么办!也看看:[我可以取标准库中定义的函数的地址吗?](/sf/ask/3898093111/ -在标准库中)。因此,打包成 lambda 是更好的方法。 (2认同)
  • 您通常只想要一个 \n 并且如果您还想刷新缓冲区,请明确地执行此操作。这就是为什么我说“考虑使用”而不是“你应该” (2认同)
  • @xskxzr:[不适用于一元操纵器](https://en.cppreference.com/w/cpp/language/extending_std#Addressable_functions)。 (2认同)

Jar*_*d42 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));
Run Code Online (Sandbox Code Playgroud)

否则你必须指定你想要的

print(1, 2, 3, std::endl<char, std::char_traits<char>>);
Run Code Online (Sandbox Code Playgroud)

或包裹它

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

演示