【问题标题】:C++ concepts see a function for my type, but don't see it for std::vectorC++ 概念看到我的类型的函数,但看不到 std::vector
【发布时间】:2019-06-08 20:25:18
【问题描述】:

我正在尝试使用 Functor、Monoid 等类型类在 C++ 中实现类似 Haskell Prelude 之类的东西。所以我决定使用 C++ Concepts 进行类型检查,但在尝试实现 Semigroup 概念时遇到了问题。

当我尝试声明一个使用某些函数的概念时出现问题.

完整代码:

template<class T>
struct S {
    // ...
};

template<class T>
concept Addable = requires(T a, T b) {
    { add(a, b) } -> T;
};

template<class T>
S<T> add(const S<T> & a, const S<T> & b) {
    // ...
    return {};
}

template<class T>
std::vector<T> add(const std::vector<T> & a, const std::vector<T> & b) {
    // ...
    return {};
}

int main() {
    std::cout << Addable<S<int>> << '\n';
    std::cout << Addable<std::vector<int>> << '\n';
}

我希望输出1 1,但实际输出是1 0。 因此,无论声明的 add(std::vector) 重载如何,它都不会将 std::vector 识别为 Addable,但它确实将 S 类型识别为 Addable。

统一更新: 如果我将add 函数移到Addable 概念之前,问题就会消失。但是,在包含这些概念之前,我必须实现我为 std::vector 之类的类型包含的所有概念,这看起来非常不方便且不清楚。

UPD2: 我使用 GCC 9.1.0。

【问题讨论】:

  • 我的猜测是,Addable 通过与参数相关的查找为S 找到add,但不能为vector 做同样的事情,因为类和函数位于不同的命名空间中.如果在Addable 之前声明或定义add 是否有效?
  • @chris 就像我想的那样——一旦你将Addable 向下移动,所以add 对普通查找可见,程序会打印1 1
  • 请注意,如果您未能通过重载决议检查as seen here,Clang 会为您提供一些关于为什么的更多信息。
  • @IgorTandetnik 这是否意味着如果我有来自 stl 的 std::vector 和来自第三方库的一些 Addable 概念,我将无法为 @987654340 实现该概念@?或者我只能通过在包含Addable 的标题之前放置add 来做到这一点?

标签: c++ templates stdvector c++-concepts


【解决方案1】:

我认为这是这个实验性 Clang 概念实现的缺陷。 [temp.concept]/8 说:

概念未实例化 ([temp.spec])。

另见:In which access control context are evaluated concepts?

这意味着[temp.res] 中描述的名称解析不适用于作为概念定义的表达式。如果必须实例化概念,则无法通过非限定名称查找找到函数add。这就是 Clang 产生错误的原因。

根据标准,当 id 表达式命名一个概念时,normalized 约束表达式在出现 id 表达式 ([expr.prim.id]/4) 的位置进行计算。

不太正式地,作为概念定义的表达式是在命名概念的表达式的上下文中计算的。所以Addable&lt;vector&lt;int&gt;&gt; 应该为真,因为在这个表达式的上下文中,add 可以通过非限定名称查找找到。

【讨论】:

  • 不是clang特定的,gcc 9.1的结果是一样的。
  • @bipil 最初是函数或变量类型的概念。第 I 段站点比较新:它是去年添加到标准中的,它不是 TS 概念的一部分。
猜你喜欢
  • 2018-12-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-07-24
  • 2017-09-09
  • 1970-01-01
  • 2018-05-31
  • 1970-01-01
相关资源
最近更新 更多