当用作概念的默认参数时,非重载函数会产生未解决的重载错误
Non-overloaded function yields unresolved overloaded error when used as default argument for concept
背景
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 {};
编译没有错误。
问题
- 这是否源于 背景 中的错误但显示不同的消息?
- 如果不是,为什么会显示与重载函数相关的错误?
- Is this derived from the error in Background but showing a different message?
不,这完全无关。背景错误是试图将类型作为默认参数传递给需要模板的参数:这只是错误的 kind 参数。
- 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
作为默认参数可以正常工作,因为它已经是一个类型,所以它可以正常工作。
背景
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 {};
编译没有错误。
问题
- 这是否源于 背景 中的错误但显示不同的消息?
- 如果不是,为什么会显示与重载函数相关的错误?
- Is this derived from the error in Background but showing a different message?
不,这完全无关。背景错误是试图将类型作为默认参数传递给需要模板的参数:这只是错误的 kind 参数。
- 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
作为默认参数可以正常工作,因为它已经是一个类型,所以它可以正常工作。