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

问题描述

背景

根据[temp.arg.template]/1

模板模板参数的模板参数应该是类模板或别名模板的名称,表示为 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)被一个仿函数替换,它是一个类模板,

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. 如果不是,它为什么会显示与重载函数相关的错误?

标签: c++templateslanguage-lawyerc++20c++-concepts

解决方案


  1. 这是否源自背景中的错误但显示不同的消息?

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

  1. 如果不是,它为什么会显示与重载函数相关的错误?

您尝试做的事情减少到:

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

没有一种类型func-func不是函数,而是函数模板。它可用于实例化具有许多不同类型的许多不同函数。这里没有足够的信息来选择正在选择的重载。

您必须手动选择,如:

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

另请参阅此问题

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


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


推荐阅读