"template T is a..."形式的条件如何用概念表达?

How to express conditions of the form "template T is a..." using concepts?

很容易表达"type T is a container of E":

template <class T, class E>
concept bool is_container = requires(T t, E e) {
    { t.push_back(e) } -> void;
};

template <class T, class E> requires is_container<T,E>
void moo()
{
    T t; E e;
    t.push_back(e);
}

(具体检查什么并不重要)

现在我需要这样表达一个条件:"for any type E, T is a container".

template <template<class> class T> requires is_container<T>
void moo()
{
    T<int> ti; 
    ti.push_back(1);
    T<std::string> ts;
    ts.push_back("abc"s);
}

这种情况下is_container怎么写?

基本上,您所要求的内容不可能按照您暗示的方式实现,但通过简单的解决方法,您可以获得相同的结果。

要知道 T<E> 是任何类型 E 的容器,编译器需要为每个可能的 E 实例化 T<E> 并检查条件,这是不可能的,因为有无限多种可能的类型T<E>(想象一下链T<T<E>>)。

您可以做的是从公共基础 class(标签)派生所有容器 classes(那些是任何 E 的容器)。

struct container_tag { };

template<class E>
class existing_container_class : public container_tag
{
public:
    using value_type = E;
    /* ... */
};

然后写一个这样的概念:

template<class T>
concept bool concept_container = std::is_base_of_v<container_tag, T>;

并像这样使用它:

template<concept_container T>
void moo() {
    T t;
    T::value_type e;
    t.push_back(e);
}

中的许多不可能的事情一样,这相当于解决了Halt。

您有一个图灵完备语言的任意函数(您的模板),并希望确定您的函数的每个输出(模板的每个实例)是否满足某些 属性。

莱斯定理说这是不可能的。

这是像模板这样的图灵完备元编程语言的缺点之一。

现在您可以随身携带模板并根据特定类型进行检查。但是在一个足够复杂的程序中,这很像发明用来解决问题的概念;接口错误而不是深度实现错误。

缺少 C++ 模板 parametricity。给定一个模板,只能检查其特定实例的属性,而不能检查模板本身(或 "all its instantiations",可以说是)。不同的实例化可能有不同的属性。

所以显然不可能写出像is_container的第二种变体这样的概念。

这是一个非常简单、老套的部分解决方法。这个想法是,如果一个模板实例化并适用于某种随机类型,它也可能适用于其他类型。当然,不受控制的专业化和高级模板魔术会打破这个假设,但我们只是回到了常规未经检查的模板的原点。

template <class T, class E>
concept bool is_container = requires(T t, E e) {
    { t.push_back(e) } -> void;
};

struct random {};

template <template<class> class T>
concept bool is_generic_container = is_container<T<random>, random>;