函数名不代表函数;它是函数名的重载集。
你的功能
void foo(auto const &){}
似乎正在使用该语言的概念式扩展来实现简洁的模板功能。在标准 C++ 中,它会显示为:
template<class T>
void foo(T const &){}
模板函数不是函数。它是由该模板生成的一组重载函数。
函数名的重载集不是 C++ 对象。您可以传递给函数的东西是 C++ 对象。
现在,当函数名的重载集只命名一个函数时,编译器会自动解析重载并为您提供该函数对象。
当函数名称的重载集被转换为具有固定签名的指向函数的指针时,重载决议就会启动并(希望)选择一个。
但是,在调用for_each
时,参数不是特定的固定签名函数指针。相反,它是一个泛型类型参数。此时,编译器无法解析函数名的重载集。你想要哪一个是模棱两可的。
有两种解决方案。其中之一是将您的函数重载集转换为特定的函数指针。这要求你是明确的。
第二个是将您的重载集顶部包装到一个对象中。您可以使用带有模板的手动函数对象来执行此操作operator()
,或者在 C++14 中您可以执行此操作:
#define OVERLOADS_OF(...) \
[](auto&&...args) \
noexcept(noexcept(__VA_ARGS__(decltype(args)(args)...))) \
->decltype( __VA_ARGS__(decltype(args)(args)...) ) \
{ return __VA_ARGS__(decltype(args)(args)...); }
它构建了一个无状态 lambda,表示全局函数名的重载。
所以:
void foo(auto const &){}
auto const rng{ranges::view::all(v)};
ranges::for_each(rng, OVERLOADS_OF(foo));
如果你想捕捉更少的极端情况,一个简单的:
void foo(auto const &){}
auto const rng{ranges::view::all(v)};
ranges::for_each(rng, [](auto&x){foo(x);});
也适用于这种特定情况。
顺便说一句,有一个 C++20 提议替换OVERLOADS_OF(foo)
为[](auto&&...args)=>foo(decltype(args)(args)...)
(产生与宏相同的效果)。可悲的是,decltype
和noexcept
功能被否决了。