C++有什么方法可以在既不调用函数模板也不提供其模板参数的情况下引用函数模板?

Is there any way in C++ to refer to a function template while neither calling it nor supplying its template parameters?

本文关键字:函数模板 参数 引用 情况下 方法 C++ 调用 什么      更新时间:2023-10-16

这是我想要工作的代码:

template <class T> void Foo(T&& param);
template <class F> void CallMe(F&& func)
{
func(42);
}
int main()
{
CallMe(Foo);
}

编译器在尝试实例化CallMe时会窒息,因为它不知道我所说的Foo是什么意思。 当然,如果我写Foo<int>,它会起作用,但我想避免这种情况,因为在实际代码中,模板参数可能很复杂。

我目前的解决方法是使用可调用对象而不是自由函数。 例如:

class Foo
{
public:
template <class T> void operator()(T&&);
};

这工作正常,但我相信它会让我的库的用户感到困惑。 我可以使用一些模板魔法来使第一个版本工作吗?

我可以使用一些模板魔法来使第一个版本工作吗?

但愿。我希望有一天。在这方面已经有几项建议(例如P0119和P0834(。在那之前,你能做的最好的事情就是编写一个提升宏,将你的名字变成一个调用该名字的函数对象:

#define FWD(...) std::forward<decltype(__VA_ARGS__)>(__VA_ARGS__)
#define LIFT(name) [&](auto&&... args)     
noexcept(noexcept(name(FWD(args)...))) 
-> decltype(name(FWD(args)...))        
{ return name(FWD(args)...); }

这使您可以编写:

CallMe(LIFT(Foo));

否则可以做你想要的。

可以制作一些与问题中的代码有点相似的东西,但不完全是。

函数调用:

int main()
{
CallMe(Foo);
}

需要一个对象作为参数。对象可以是函数指针、类实例、lambda 或类似的东西。它不能是未实例化的模板函数,因为它不是对象。只有实例化的函数才是对象。

正如原始问题所述,使用类似函数的对象是一种变通方法,并假设以下内容对某些用户来说太混乱了:

class Foo
{
public:
template <class T> void operator()(T&&);
};

取而代之的是,可以使用通用 lambda,它基本相同,但没有所有的样板。通用 lambda 看起来几乎像一个常规函数:

auto Foo = [](auto x) 
{ 
std::cout << x << 'n';
};
int main()
{
CallMe(Foo);
}

我可以使用一些模板魔法来使第一个版本工作吗?

不。

函数模板的名称不是函数类型,而是函数类型的系列。如果可能的话,func的类型将从中推导出来FooT的类型将保持非推导,这是实例化Foo所必需的。

#define RETURNS(...) 
noexcept(noexcept(__VA_ARGS__)) 
-> decltype(__VA_ARGS__) 
{ return __VA_ARGS__; }
#define OVERLOADS_OF(...) 
[](auto&&...args) 
RETURNS( __VA_ARGS__( decltype(args)(args)... ) )

然后

CallMe(OVERLOADS_OF(Foo));

创建一个函数对象,该对象表示名称Foo的重载,其中包括由名为Foo的模板函数生成的函数。

RETURNS在其他上下文中也很有用。 @Barry有一个建议,使RETURNS(X)类似于=> X,至少对于lambdas。