在没有结构样板代码的情况下约束模板参数的简短方法

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

考虑这个例子:

#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";
}

C++20 有更短的方法吗?我知道你可以为“专门化模板”做一个概念,例如:

// 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>;

但是,使用非类型模板参数(例如“size_t”)会失败。有没有办法让我可以,例如只写:

void test(Foo auto xy);

我知道自从 C++20 以来,出现了一些其他方法来约束函数的模板参数,但是,有没有一种简短的方法可以说“我不在乎它如何专门化结构,只要它是吗?

没有。

无法编写适用于具有所有类型参数的模板和 std::array(即您的 Foo)之类的模板的通用 is_specialization_of,因为无法编写采用任何 kind.

参数的模板

有一项语言功能提案允许 (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) 提供一种方法来执行此操作(除了您必须拼写概念 Specializes<^Foo> 而不是 Specializes<Foo>).

在这些事情发生之前,您要么为模板编写定制概念,要么重写模板以仅采用类型参数。