【问题标题】:Is there a hack to defer non-ADL name lookup to the point where a C++ concept is used?是否存在将非 ADL 名称查找推迟到使用 C++ 概念的技巧?
【发布时间】:2021-06-16 18:05:05
【问题描述】:

我正在尝试使用适用于内置类型和用户定义类型的概念。在我的设置中,前向声明某些函数很不方便(因为这些函数间接依赖于导致我的问题的概念)。

我的问题是,如果这些函数具有内置类型的参数,则概念无法识别先前未声明的函数。这是一个最小的非工作示例:

struct S {};

// void func(bool);  // Works if this line uncommented

template<typename T> concept has_func =
  requires(T t) { func(t); };

void func(S) {}
static_assert(has_func<S>); // OK

void func(bool) {}
static_assert(has_func<bool>); // Error

我的第一个问题:为什么会发生这种情况?我怀疑它与 ADL 有关,因为即使一切都在全局命名空间中,全局命名空间仍然是一个命名空间,而内置的 bool 在技术上并不在该命名空间中。所以不知何故,我需要用一些捕获 bool 行为的用户定义类型来表达这个概念。

我的第二个问题:推迟对我的函数进行名称查找的好方法是什么?我的后备(因为我无法在我的实际代码中前向声明)是将概念重新定义为std::same_as&lt;T, bool&gt; || ...。但是,我想知道是否有更通用的技巧可以将名称查找推迟到使用该概念的地步。我尝试过使用requires(std::type_identity_t&lt;T&gt; t) 之类的方法,但没有帮助。

更新:

我没有解决此问题的技巧,但我知道它是由dependent name lookup rules 引起的。具体来说:

  • 非 ADL 查找检查具有从模板定义上下文可见的外部链接的函数声明
  • ADL 检查具有从模板定义上下文或模板实例化上下文可见的外部链接的函数声明

所以我尝试过的两件事是:

  1. 使用触发 ADL 的类型的额外参数调用其他函数 dofunc。那种工作,除了这个函数需要调用func,所以dofunc 函数的位置现在变得很棘手,因为func 在范围内。它并没有真正改善事情。

  2. 将某种代理类型与运算符 bool 一起使用,但这不起作用,因为它不会触发我要调用的函数的 ADL。

可能我想要做的事情是不可能的,以避免出现概念在不同上下文中具有不同含义的情况。当然,对于 ADL,这个概念在不同的上下文中可能会有所不同,具体取决于使用该概念时的范围,所以我仍然没有真正理解这种限制的理由。

【问题讨论】:

  • @NicolBolas 我有一个解决方案,只是将std::same_as&lt;T, bool&gt; || 添加到我的概念中。递归不是问题,因为它很快就会触底,所以实际上并没有像非 ADL 问题那样的递归问题
  • 在概念中添加std::same_as&lt;T, bool&gt; || 会不会像前向声明void func (bool) 一样烦人?
  • @Frank 不,因为没有 foo(bool) 函数可以转发声明。有一个 foo(some_other_concept auto t) 函数恰好接受一个布尔值。
  • @Frank Barry 的answer 在您链接的问答中may work,但它有点丑。
  • @Bob__ 在这一点上,为什么不把same_as&lt;T,bool&gt; 放在概念中呢?只有有限数量的内置类型,所以不妨在概念中枚举它们,而不是在其他类中枚举它们。我只是希望你能做一些事情,比如将 bool 转换为与 bool 等效但会触发 ADL 的东西。

标签: c++ c++20 c++-concepts argument-dependent-lookup


【解决方案1】:

是的,您的初始代码中的static_assert(has_func&lt;bool&gt;) 不起作用,因为bool 是内置类型,因此不会执行与参数相关的查找(ADL)并且func(bool) 必须在概念定义中可见。

我认为您可以利用代理类型 A&lt;T&gt; 和 ADL 来制作一个接受内置类型的类似概念:

template<class T>
struct A{
    operator T() const;
};

template<typename T> concept has_func =
  requires { func(A<T>{}); };

// Some tests:
void func(bool&) {}
static_assert(has_func<bool&>);
static_assert(!has_func<int>); // func(1) is not valid

void func(bool) {}
static_assert(has_func<bool>);

struct S{};
void func(S) {}
static_assert(has_func<S>);

演示:https://gcc.godbolt.org/z/bGY8zGes9

【讨论】:

    猜你喜欢
    • 2022-01-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多