1
votes

Background

As per [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.

which means that it is not possible to pass a function template as a default template template argument.

As expected, the following code snippet:

template <typename>
void func() {}

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

results in the error below (Clang):

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

Problem

However, when a function template is provided as a default template template argument constrained by concept, this raises a different error:

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 {};

This, surprisingly, yields an overloaded error:

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

When decltype(&func) is replaced with a functor, which is a class template,

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 {};

This compiles without an error.

Question

  1. Is this derived from the error in Background but showing a different message?
  2. If not, how come it shows an error related to an overloaded function?
1

1 Answers

0
votes
  1. Is this derived from the error in Background but showing a different message?

No, it's totally unrelated. The background error is trying to pass in a type as a default argument for a parameter expecting a template: it's just the wrong kind of argument.

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

What you're trying to do reduces to:

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

There is no one type of func - func isn't a function, it's a function template. It can be used to instantiate many different functions which have many different types. There's not enough information here to pick which overload that is being selected.

You'd have to manually choose, as in:

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

See also this question.

The fact that the parameter that decltype(&func) is intended to be a default argument for is constrained by invocable doesn't matter - that information doesn't participate in the overload resolution necessary to pick which func is the desired one.


Providing Functor as a default argument works fine because that is already a type, so it just works.