Search code examples
c++c++20template-specializationnon-type-template-parameter

Short way to constrain template parameter without boiler plate code for a struct


consider this example:

#include <iostream>
template <typename T, std::size_t I>
struct Foo
{
  
};

template <typename T>
struct specializes_foo : std::false_type {};

template <typename T, std::size_t I>
struct specializes_foo<Foo<T, I>> : std::true_type {};
  
template <typename T>
concept foo = specializes_foo<T>::value;

int main()
{
  std::cout << foo<int> << "\n";
  std::cout << foo<Foo<int,3>> << "\n";
}

is there a shorter way in C++20? I know that you could do a concept for "specializes template", e.g.:

// checks if a type T specializes a given template class template_class
// note: This only works with typename template parameters. 
// e.g.: specializes<std::array<int, 3>, std::array> will yield a compilation error.
//       workaround: add a specialization for std::array.

namespace specializes_impl
{
template <typename T, template <typename...> typename>
struct is_specialization_of : std::false_type {};

template <typename... Args, template <typename...> typename template_class>
struct is_specialization_of<template_class<Args...>, template_class> : std::true_type {};
}

template <typename T, template <typename...> typename template_class>
inline constexpr bool is_specialization_of_v = specializes_impl::is_specialization_of<T,template_class>::value;

template <typename T, template <typename...> typename template_class>
using is_specialization_of_t = specializes_impl::is_specialization_of<T,template_class>::type;


template<typename T, template <typename...> typename template_class>
concept specializes = is_specialization_of_v<T, template_class>;

However, this fails with non-type template parameters such as "size_t". Is there a way so I could, for example just write:

void test(Foo auto xy);

I know that since C++20 there came a couple of other ways to constrain template parameters of a function, however, is there a short way to say "I dont care how it specializes the struct as long as it does"?


Solution

  • Nope.

    There's no way to write a generic is_specialization_of that works for both templates with all type parameters and stuff like std::array (i.e. your Foo), because there's no way to write a template that takes a parameter of any kind.


    There's a proposal for a language feature that would allow that (P1985), but it's still just a proposal and it won't be in C++23. But it directly allows for a solution for this. Likewise, the reflection proposal (P1240) would allow for a way to do this (except that you'd have to spell the concept Specializes<^Foo> instead of Specializes<Foo>).

    Until one of these things happens, you're either writing a bespoke concept for your template, or rewriting your template to only take type parameters.