C++ 概念看到我的类型的函数,但看不到 std::vector 的函数

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

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

当我尝试声明一个使用某些函数的概念时出现问题,该函数在代码后面为所需类型声明和重载,但它仅与某些类型相关,如 std::vector,但对于我自己的类型效果很好.

完整代码:

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。

最佳答案

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

A concept is not instantiated ([temp.spec]).

另请参阅:In which access control context are evaluated concepts?

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

根据标准,当一个 id-expression 命名一个概念时,normalized constraint-expression 在出现 id-expression ( [expr.prim.id]/4 ) 的地方计算。

通俗地说,作为概念定义的表达式是在命名概念的表达式的上下文中求值的。所以Addable<vector<int>>应该是真的,因为在这个表达式的上下文中,add可以通过非限定名称查找找到。

关于C++ 概念看到我的类型的函数,但看不到 std::vector 的函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56509883/

相关文章:

c++ - WinInet ftp 连接错误 123

c++ - 需要在 else 部分访问值为 5 的变量 x

c++ - 通过对象指针访问成员

c++ - 是否有将范围移动到 vector 中的标准方法?

c++ - vector 对统一初始化

c++ - numeric_limits 不适用于引用类型是否有原因?

c++ - 将访问者模式与模板派生类一起使用

c++ - 显式模板特化

c++ - 类引用授予对私有(private)成员的访问权限

c++ - 在 vector 声明中初始化对象