Template function specialization for specific template ( not type )

Solution 1:

One common workaround would go like this:

template <typename T> 
struct FuncImpl {
  static void Run() { std::cout << "Default"; }
};

template <typename T> 
struct FuncImpl<A<T>> {
  static void Run() { std::cout << "Specialized for A<T>"; }
};

template <typename T>
void Func() { FuncImpl<T>::Run(); }

Function templates cannot be partially specialized, but class templates can be; so we just delegate from the former to the latter.

Solution 2:

It feels a bit complicated to me. Can that be simplified? Would be nice if the Check template can be removed. Any idea?

Much of complexity and in-elegance is in the fact you need a new concept for every class template. Write a general-purpose and reusable concept, and it is no longer complicated to use.

template <typename T, template <typename...> class TT>
constexpr bool is_instantiation_of_v = false; 

template <template <typename...> class TT, typename... TS>
constexpr bool is_instantiation_of_v <TT<TS...>, TT> = true;

template <class C, template<typename...> class TT>
concept instantiation_of = is_instantiation_of_v<C, TT>;

The same principle as yours, except the checker is usable with a template taking any number of type arguments. Meanwhile, the concept accepts the same parameters. The first parameter has a special meaning and is implicitly understood to be the constrained template parameter in the short-hand syntax. The rest (the template template-parameter) must be given explicitly.

How can it be used? Like this

template <instantiation_of<A> T>
int Func()
{
    return 'A';
}

template <instantiation_of<B> T>
int Func()
{
    return 'B';
}

Got a new class template to constrain over? No problem, this concept works without additional boiler-plate.

template <instantiation_of<D> T>
int Func()
{
    return 'D';
}

Solution 3:

OP writes:

Yes, would be nice to write some "instant" code directly in the functions template parameter... if possible...

Normally, to determine whether it's a specialization of some given class template, we define a trait ahead of time and then check whether the type satisfies that trait. If you don't want to define anything ahead of time, you have to find a way to perform template argument deduction inline, so you can check whether it succeeds. In C++20, this is straightforward but a bit ugly:

template <typename T> 
void Func()
{
    std::cout << "unconstrained" << std::endl;
}

template <typename T>
requires requires {
    []<typename U>(const A<U>&){}(std::declval<T>());
}
void Func()
{
    std::cout << "constrained" << std::endl;
}

Here, the requires-clause checks whether T can be bound to an argument of type const A<U>& for some deducible U. You can see this example here: https://godbolt.org/z/dTEbaaPvh

This isn't exactly pleasant to read. If you will be using this hack multiple times, I think it's better to just define traits instead. I've answered your question simply to satisfy your curiosity, not to recommend this technique.

The version above will pick the constrained version not only when the template argument is some A<U> but also when it is possibly cv-qualified, possibly ref-qualified, and possibly publicly derived from A<U>. Some tweaks are possible to make the constraint more strict.