C ++规范的哪一部分限制了参数依赖查找,从相关名称空间集中查找函数模板?换句话说,为什么最后一个呼唤 main 以下无法编译?

namespace ns {
    struct foo {};
    template<int i> void frob(foo const&) {}
    void non_template(foo const&) {}
}

int main() {
    ns::foo f;
    non_template(f); // This is fine.
    frob<0>(f); // This is not.
}
有帮助吗?

解决方案

这部分解释了:

C ++标准03 14.8.1.6:

注意:对于简单的函数名称,即使在呼叫范围内不可见函数名称,也适用参数依赖的查找(3.4.2)。这是因为调用仍然具有函数调用的句法形式(3.4.1)。但是,当使用带有显式模板参数的函数模板时,呼叫没有正确的句法形式,除非有一个函数模板在呼叫点可见。如果看不到此类名称,则该调用在句法上不正确,并且不适用参数依赖性查找。如果某些名称可见,则适用参数依赖性查找,并且可以在其他名称空间中找到其他功能模板。

namespace A {
  struct B { };
  template<int X> void f(B);
}
namespace C {
  template<class T> void f(T t);
}
void g(A::B b) {
  f<3>(b);    //ill-formed: not a function call
  A::f<3>(b); //well-formed
  C::f<3>(b); //ill-formed; argument dependent lookup
              // applies only to unqualified names
  using C::f;
  f<3>(b);    //well-formed because C::f is visible; then
              // A::f is found by argument dependent lookup
}

其他提示

我想完善略微接受的答案。在OP问题中尚不清楚,但是标准(Kornel引用)的重要部分是(重点是我的):

但是当功能模板带有 显式模板参数 使用,呼叫没有正确的句法形式

因此,禁止的是依靠ADL并使用显式模板参数。不幸的是,使用非类型模板参数需要使用显式参数(除非它们具有默认值)。

以下是显示此信息的示例代码:

居住

#include <string>
#include <utility>

namespace C {
  struct B { };
  template<class T> void f(T t){}
}

void g(C::B b) {
  f(b);           // OK
  //f<C::B>(b);   // ill-formed: not a function call, but only 
                  //  because explicit template argument were used

  std::string s;
  move(s);                      // OK
  //move<std::string&>(s);      // Error, again because 
                                //  explicit template argument were used
  std::move<std::string&>(s);   // Ok
}

int main()
{
 C::B b;
 g(b);
}

由于C ++ 20,ADL在显式函数模板上也可以正常工作。这是提议:P0846R0:ADL和功能模板不可见:

提出了对查找规则的修订,而不是要求用户使用模板关键字,以便将正常查找的名称无效或找到一个或多个函数,然后随后aa“ <”将被视为如果找到了功能模板名称并将导致ADL执行。

当前,只有GCC 9已实现此功能,因此您的示例可以编译。

live demo.

编辑:不,这是不对的。看 @Kornel的答案.


我不确定,但是在咨询了Stroustrup的“ C ++编程语言”之后,我认为附录C第13.8.4节 可能 成为原因。

自从 frob 是一个模板,可以想象是否会专业 i=0 在您打电话后的某个时刻。这意味着该实施将为选择哪种可能的方法 frob 看来可以在实例化时选择它 或者 在处理翻译单元结束时。

所以,我认为问题是你可以做

namespace ns {
    struct foo {};
    template<int i> void frob(foo const&) {}
}

int main() {
    ns::foo f;
    frob<0>(f);
    return 0;
}

namespace ns {
    template<> void frob< 0 >(foo const&) { /* Do something different*/ }
}
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top