当用作概念的默认参数时,非重载函数会产生未解决的重载错误

Non-overloaded function yields unresolved overloaded error when used as default argument for concept

背景

根据[temp.arg.template]/1,

A template-argument for a template template-parameter shall be the name of a class template or an alias template, expressed as id-expression.

这意味着无法将函数模板作为默认模板模板参数传递。

不出所料,以下代码片段:

template <typename>
void func() {}

template <template <typename> typename Wrapper = decltype(&func)>
struct Foo {};

导致以下错误 (Clang):

error: default template argument for a template template parameter must be a class template
template <template <typename> typename Wrapper = decltype(&func)>

问题

但是,当函数模板作为受概念约束的默认模板模板参数提供时,会引发不同的错误:

void placeholder() {}

void func(std::invocable auto f) {}

template <typename Fn, typename FnArg>
concept FooConcept = std::is_invocable_v<FnArg>;

template <FooConcept<decltype(&placeholder)> Wrapper = decltype(&func)>
struct Foo {};

令人惊讶的是,这会产生一个过载错误:

error: reference to overloaded function could not be resolved; did you mean to call it?
template <FooConcept<decltype(&placeholder)> Wrapper = decltype(&func)>
海湾合作委员会
error: 'decltype' cannot resolve address of overloaded function
   99 | template <FooConcept<decltype(&placeholder)> Wrapper = decltype(&func)>

decltype(&func) 被替换为仿函数,即 class 模板时,

void placeholder() {}

template <typename Fn, typename FnArg>
concept FooConcept = std::is_invocable_v<FnArg>;

struct Functor {
    auto operator()(std::invocable auto f) -> void {}
};

template <FooConcept<decltype(&placeholder)> Wrapper = Functor>
struct Foo {};

编译没有错误。

问题

  1. 这是否源于 背景 中的错误但显示不同的消息?
  2. 如果不是,为什么会显示与重载函数相关的错误?
  1. Is this derived from the error in Background but showing a different message?

不,这完全无关。背景错误是试图将类型作为默认参数传递给需要模板的参数:这只是错误的 kind 参数。

  1. If not, how come it shows an error related to an overloaded function?

您要执行的操作简化为:

void func(auto f) {}
using T = decltype(&func); // error

没有一个类型的func - func不是一个函数,它是一个函数模板。它可用于实例化许多具有许多不同类型的不同函数。此处信息不足,无法选择正在选择哪个 重载。

您必须手动选择,如:

using T = decltype(static_cast<void(*)(int)>(func)); // ok

另见 this question

decltype(&func) 旨在作为默认参数的参数受 invocable 约束的事实无关紧要 - 该信息不参与选择所需的重载决议其中 func 是所需的。


提供 Functor 作为默认参数可以正常工作,因为它已经是一个类型,所以它可以正常工作。