我无意在实际代码中使用它.我承诺.
std当函数参数是类型container::iterator且container::iterator不是typedef内置类型时,标准是否保证找到命名空间?
例如
#include <set>
#include <algorithm>
int main()
{
std::set<int> s;
find(s.begin(), s.end(), 0); //do I have a guarantee that std::find will be found?
}
Run Code Online (Sandbox Code Playgroud)
换句话说,迭代器类是否可以在stdADL不考虑的命名空间中定义?
提前致谢.
这是如何运作的?它与ADL有关吗?
#include <iostream>
template <typename T>
struct A
{
friend void f(T x)
{
std::cout << "A\n";
}
};
int main()
{
f(new A<void*>());
}
Run Code Online (Sandbox Code Playgroud)
有人可以告诉我为什么我不能使用类似的东西
f(A<int>());
Run Code Online (Sandbox Code Playgroud) 这是来自依赖于参数的查询的后续问题,只搜索名称空间或类吗?,其中@DavidRodríguez说"ADL将查看该类型的封闭命名空间,以及类型本身内部 ".我可能错了他想说的但是我试着这个例子:
struct foo{
static void bar(foo* z){}
};
int main(){
foo* z;
bar(z);
}
Run Code Online (Sandbox Code Playgroud)
它没有编译,产生错误"'bar'未在此范围内声明".是不是ADL不考虑静态成员函数?我的意思是在示例中关联类是foo不是ADL看起来在类中?.任何人都可以在这里简化规则吗?
我正在查看关于参数依赖查找的维基百科条目,并且(2014年1月4日)给出了以下示例:
#include<iostream>
int main()
{
std::cout << "Hello World, where did operator<<() come from?" << std::endl;
}
Run Code Online (Sandbox Code Playgroud)
......有以下评论:
请注意,std :: endl是一个函数,但它需要完全限定,因为它被用作operator <<的参数(std :: endl是函数指针,而不是函数调用).
我的想法是评论不正确(或根本不清楚).我正在考虑更改评论,而不是
请注意,std :: endl需要完全限定,因为ADL不适用于函数调用的参数 ; 它只适用于函数名称本身.
我是否认为维基百科的评论不正确?我建议的改变是否正确?(即,在这个例子中,我对ADL的理解是正确的吗?)
我已经读过,当你使用swapc ++时,你应该总是using std::swap;,然后调用swap不合格,所以它会自动选择std::那些std::和内置类型,自定义类型的自定义类型,以及std::其他所有类型的模板类型.
那么,我可以只放入using std::swap;每个文件包含的标题而不必担心它吗?
我明白避免using在标题中是常见的做法.但是,在这种特殊情况下它有问题吗?
这个问题的灵感来自于这个问题.考虑一下代码:
namespace ns {
template <typename T>
void swap(T& a, T& b) {
using namespace std;
swap(a, b);
}
}
Run Code Online (Sandbox Code Playgroud)
在使用GCC进行一些测试后,我发现swap(a, b);解析为
1)std::swap如果T已经过载std::swap(例如,标准容器类型)
2)ns::swap否则,导致无限递归.
因此,似乎编译器将首先尝试在命名空间中找到匹配项ns.如果找到匹配项,则搜索结束.但是当ADL进入时并非如此,在这种情况下,std::swap无论如何都会找到.解决过程似乎很复杂.
我想知道swap(a, b)在上面的上下文中解析函数调用过程中发生了什么的细节.可以参考该标准.
c++ function-calls language-lawyer overload-resolution argument-dependent-lookup
考虑以下:
namespace N {
struct A { };
struct B {
B() { }
B(A const&) { }
friend void f(B const& ) { }
};
}
int main() {
f(N::B{}); // ok
f(N::A{}); // error
}
Run Code Online (Sandbox Code Playgroud)
在第一种情况下,案例成功 - 我们考虑相关的名称空间N::B和查找N::f(B const&).大.
第二种情况失败了.为什么?根据[namespace.memdef]:
如果
friend非本地类中的声明首先声明了类,函数,类模板或函数模板,则该友元是最内层封闭命名空间的成员.[...]如果调用了友元函数或函数模板,则可以通过名称查找找到其名称,该名称查找考虑名称空间中的函数和与函数参数类型相关联的类(3.4.2).
的关联的命名空间N::A是N,它的f一个成员,所以为什么不通过查找发现的?
c++ friend-function language-lawyer argument-dependent-lookup
在使用ADL解决这个问题后,如果传递的类型来自我们的命名空间,则可以创建一个特征来回答:
#include <utility>
namespace helper
{
template <typename T, typename = void>
struct is_member_of_sample : std::false_type
{
};
template <typename T>
struct is_member_of_sample<
T,
decltype(adl_is_member_of_sample(std::declval<T>()))> : std::true_type
{
};
}
namespace sample
{
template <typename T>
auto adl_is_member_of_sample(T && ) -> void;
}
// -- Test it
namespace sample
{
struct X;
}
struct Y;
static_assert(helper::is_member_of_sample<sample::X>::value, "");
static_assert(not helper::is_member_of_sample<Y>::value, "");
int main(){}
Run Code Online (Sandbox Code Playgroud)
由于显而易见的原因,这不能应用于std命名空间 - 根本没有办法将adl_is_member_of_sample等效命令注入std命名空间而不将自己暴露给未定义的行为.
是否有一些解决方法可以创建特征?
以下代码使用MSVC和gcc进行编译,但不能使用clang进行编译。为什么?
如果CallFoo ()is的话,似乎ADL无法正常工作constexpr。查看评论。
template <class T>
constexpr void CallFoo () // Remove constexpr to fix clang compilation error.
{
Foo (T ());
}
class Apple {};
int main ()
{
CallFoo<Apple> ();
}
constexpr void Foo (Apple)
{
}
Run Code Online (Sandbox Code Playgroud)
Clang错误消息(请参阅godbolt.org):
<source>:4:5: error: use of undeclared identifier 'Foo'
Foo (T ());
^
<source>:13:5: note: in instantiation of function template specialization 'CallFoo<Apple>' requested here
CallFoo<Apple> ();
^
Run Code Online (Sandbox Code Playgroud) 模板中使用的从属名称的查找被推迟到知道模板参数为止,这时ADL会检查具有外部链接的函数声明,这些声明从模板定义上下文或模板实例化上下文中可见。
与此相反,以下代码片段可以使用三个编译器(MSVC,clang和gcc)很好地进行编译:
template <class T>
void CallFoo ()
{
Foo (T ());
}
class Apple {};
int main ()
{
CallFoo<Apple> ();
}
static void Foo (Apple)
{
}
Run Code Online (Sandbox Code Playgroud)
Foo是以下内容中的从属名称CallFoo:它取决于模板参数T。但是,Foo尽管违反了上面引用的两个规则,但是编译器仍然可以找到该函数。
Foo从的定义或实例中都看不到的声明CallFoo,因为它位于两者之下。Foo 有内部联系。这三个编译器都不可能有错误。我可能误会了一些东西。您能详细说明一下吗?
c++ linkage dependent-name language-lawyer argument-dependent-lookup