独立的 C++ 概念能否匹配具有任何参数的特定模板?

Can a self-contained C++ concept match a particular template with any arguments?

我想要一个与特定模板类型匹配的 C++ 概念,而不管模板参数之一如何。当然,我可以使用其他一些帮助程序声明来分离模板类型来执行此操作。但是 concepts 和 requires 表达式的好处之一是它们消除了对辅助类型的许多需求。所以我想知道是否有可能通过一个概念声明来做到这一点。

这是一个最小的工作示例:

#include <algorithm>
#include <compare>
#include <iostream>
#include <memory>
#include <string>

template<typename A> using char_string =
  std::basic_string<char, std::char_traits<char>, A>;

using std::string;

template<typename T> struct AltAllocator : std::allocator<T> {};
using AltString = char_string<AltAllocator<char>>;

template<typename T> constexpr bool is_char_string_v = false;
template<typename A> constexpr bool is_char_string_v<char_string<A>> = true;

template<typename T> concept is_char_string = is_char_string_v<T>;

inline bool
operator==(is_char_string auto const &a, is_char_string auto const &b)
{
  return std::equal(a.begin(), a.end(), b.begin(), b.end());
}

int
main()
{
  string s;
  AltString as;
  std::cout << std::boolalpha << (s == as) << std::endl;
}

我希望能够定义 is_char_string 而不必引入 is_char_string_v。在这种特殊情况下,知道字符串包含它们的分配器类型,我当然可以用这样的东西“作弊”:

template<typename T> concept is_char_string =
  std::same_as<T, char_string<typename T::allocator_type>>;

是否有更通用的方法来编写与使用任何模板参数实例化的某些特定模板相匹配的自包含概念?

我不知道更广泛的问题可能是什么,但我们可以将检查某物是否为 basic_string<char, char_traits<char>, A> 的问题分解为以下问题:(1) 它是 basic_string 并且(2) 它的前两种类型是charchar_traits<char>.

第一个问题是标准is_specialization_of特征:

template <typename T, template <typename...> class Z>
inline constexpr bool is_specialization_of = false;

template <typename... Args, template <typename...> class Z>
inline constexpr bool is_specialization_of<Z<Args...>, Z> = true;

第二个我们可以使用 Boost.Mp11 进行一般类型列表操作。所以要么:

template <typename T>
concept char_string = is_specialization_of<T, std::basic_string>
                   && std::same_as<mp_first<T>, char>
                   && std::same_as<mp_second<T>, std::char_traits<char>>;

或者后两者一起检查:

template <typename T>
concept char_string = is_specialization_of<T, std::basic_string>
                   && std::same_as<
                           mp_take_c<T, 2>
                           std::basic_string<char, std::char_traits<char>
                       >;

这里只取前两个参数是安全的,因为第三个参数是默认的。由于第二个是 默认值,您可以改为比较 std::string 而不是 std::basic_string<char, std::char_traits<char>.


如果真的要避免 any 依赖项或 any 其他类型,那么我想你可以这样写:

template <typename T>
concept char_string = requires (T t) {
    []<typename A>(std::basic_string<char, std::char_traits<char>, A>){}(t);
};

但我不确定这是个好主意。