2

很容易表达“类型 T 是 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);
}

(具体检查的内容并不那么重要)。

现在我需要表达这样一个条件:“对于任何类型的 E,T 都是一个容器”。

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

4

3 回答 3

4

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

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

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

这是图灵完备的元编程语言(如模板)的缺点之一。

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

于 2017-10-31T12:58:08.853 回答
3

C++ 模板缺乏参数化。给定一个模板,只能检查其特定实例的属性,而不能检查模板本身(或“它的所有实例”,可以说是)。不同的实例可能具有不同的属性。

所以显然不可能写出像is_container.

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

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>;
于 2017-10-31T13:22:53.197 回答
1

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

要知道它T<E>是任何类型的容器E,编译器需要T<E>对所有可能E的情况进行实例化并检查条件,这是不可能的,因为有无限多的可能类型T<E>(例如链T<T<E>>)。

您可以做的是E从公共基类(标签)派生所有容器类(那些是 any 的容器)。

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);
}
于 2017-10-31T12:39:09.167 回答