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

余生长醉 提交于 2019-12-10 11:16:18

问题


Here's the code I would like to work:

template <class T> void Foo(T&& param);

template <class F> void CallMe(F&& func)
{
    func(42);
}

int main()
{
    CallMe(Foo);
}

The compiler chokes when it tries to instantiate CallMe because it doesn't know what I mean by Foo. It works if I write Foo<int> of course, but I'd like to avoid that because in the real code the template parameters can be complex.

My current workaround is to use callable objects instead of free functions. For example:

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

This works fine, but I'm sure it will confuse users of my library. Is there some template magic I can use to make the first version work?


回答1:


Is there some template magic I can use to make the first version work?

I wish. And I hope someday. There have been several proposals in this area (e.g. P0119 and P0834). Until then, the best you can do is write a lifting macro to turn your name into a function object that calls that name:

#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)...); }

This lets you write:

CallMe(LIFT(Foo));

which otherwise does what you want.




回答2:


It is possible to make something that somewhat resembles the code in the question, but not exactly.

A function call:

int main()
{
    CallMe(Foo);
}

expects an object as a parameter. The object can be a function pointer, a class instance, a lambda, or something similar. It can't be an uninstantiated template function, since it is not an object. Only an instantiated function is an object.

As the original question states, using function-like objects is a work-around, and assumes that the following is too confusing for some users:

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

Instead of that, it is possible to use a generic lambda, which is basically the same, but without all the boiler plate. A generic lambda looks almost like a regular function:

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



回答3:


Is there some template magic I can use to make the first version work?

No.

The name of a function template don’t name a function type but a family of them. If it were possible, and the type of func would be deduced from Foo the type of T will remain non-deduced which is needed in order to instantiate the Foo.




回答4:


#define RETURNS(...) \
  noexcept(noexcept(__VA_ARGS__)) \
  -> decltype(__VA_ARGS__) \
  { return __VA_ARGS__; }

#define OVERLOADS_OF(...) \
  [](auto&&...args) \
  RETURNS( __VA_ARGS__( decltype(args)(args)... ) )

then

CallMe(OVERLOADS_OF(Foo));

creates a function object that represents the overloads of the name Foo, which include the functions produced by your template function named Foo.

RETURNS is also useful in other contexts. @Barry has a proposal to make RETURNS(X) be similar to => X, at least for lambdas.



来源:https://stackoverflow.com/questions/52675813/is-there-any-way-in-c-to-refer-to-a-function-template-while-neither-calling-it

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!