在一些c ++实践中,我试图学习并采用复制交换习语,对这个问题进行彻底的解释:复制交换习语.
但我发现了一些我从未见过的代码:using std::swap; // allow ADL在这个例子中
class dumb_array
{
public:
// ...
void swap(dumb_array& pOther) // nothrow
{
using std::swap; // allow ADL /* <===== THE LINE I DONT UNDERSTAND */
swap(mSize, pOther.mSize); // with the internal members swapped,
swap(mArray, pOther.mArray); // *this and pOther are effectively swapped
}
};
Run Code Online (Sandbox Code Playgroud)
using std::swap;在函数实现的主体内部意味着什么?考虑以下C++程序:
#include <memory>
struct A {};
struct B : A {};
int main()
{
auto x = std::make_shared<A>();
if (auto p = dynamic_pointer_cast<B>(x));
}
Run Code Online (Sandbox Code Playgroud)
使用MSVC 2010进行编译时,我收到以下错误:
error C2065: 'dynamic_pointer_cast' : undeclared identifier
Run Code Online (Sandbox Code Playgroud)
如果auto被替换,则错误仍然存在std::shared_ptr<A>.当我完全符合要求时std::dynamic_pointer_cast,程序会成功编译.
另外,gcc 4.5.1也不喜欢它:
error: 'dynamic_pointer_cast' was not declared in this scope
Run Code Online (Sandbox Code Playgroud)
我认为Koenig查找std::dynamic_pointer_cast会选择它,因为命名空间中的生命类型.我在这里错过了什么?xstd
让我们在声明中定义f:作为朋友的函数:SS
struct S
{
friend void f() {}
};
Run Code Online (Sandbox Code Playgroud)
我找不到打电话的方法f.
struct S
{
friend void f() {}
friend void g(S const&) {}
} const s;
int main()
{
// f(); // error: 'f' was not declared in this scope
// S::f(); // error: 'f' is not a member of 'S'
g(s);
// S::g(s); // error: 'g' is not a member of 'S'
}
Run Code Online (Sandbox Code Playgroud)
额外奖励:如果我想获得函数指针/ std::function/ lambda g怎么办?
c++ friend language-lawyer name-lookup argument-dependent-lookup
可能重复:
为什么ADL没有找到功能模板?
调用get似乎不会调用依赖于参数的查找:
auto t = std::make_tuple(false, false, true);
bool a = get<0>(t); // error
bool b = std::get<0>(t); // okay
Run Code Online (Sandbox Code Playgroud)
g ++ 4.6.0说:
error: 'get' was not declared in this scope
Run Code Online (Sandbox Code Playgroud)
Visual Studio 2010说:
error C2065: 'get': undeclared identifier
Run Code Online (Sandbox Code Playgroud)
为什么?
以下程序
#include <algorithm>
#include <utility>
#include <memory>
namespace my_namespace
{
template<class T>
void swap(T& a, T& b)
{
T tmp = std::move(a);
a = std::move(b);
b = std::move(tmp);
}
template<class T, class Alloc = std::allocator<T>>
class foo {};
}
int main()
{
my_namespace::foo<int> *a, *b;
using my_namespace::swap;
swap(a,b);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
导致两者g++并clang在我的系统上发出以下编译器错误:
$ clang -std=c++11 swap_repro.cpp -I.
swap_repro.cpp:28:3: error: call to 'swap' is ambiguous
swap(a,b);
^~~~
/usr/bin/../lib/gcc/x86_64-linux-gnu/5.2.1/../../../../include/c++/5.2.1/bits/algorithmfwd.h:571:5: note: candidate function [with _Tp = my_namespace::foo<int, std::allocator<int> > …Run Code Online (Sandbox Code Playgroud) c++ namespaces class-template name-lookup argument-dependent-lookup
我在这里有一小段代码供您考虑,这让我感到非常困惑.奇怪的是,它在Sun Studio和GCC上编译,即使我认为它不应该.
考虑一下:
namespace name
{
class C
{
int a;
};
void f(C c);
void g(int a);
}
int main(int argc, char** argv)
{
name::C c;
name::f(c);
f(c); // <--- this compiles, strangely enough
name::g(42);
// g(42); <--- this does not, as I expected
}
Run Code Online (Sandbox Code Playgroud)
来自同一命名空间的类参数会导致函数f"泄漏"到命名空间之外,并且无需访问name::.
有人对此有解释吗?这当然是我而不是编译器在这里错了.
考虑一下我在IBM网站上找到的这个例子:
#include <iostream>
using namespace std;
void f(double) { cout << "Function f(double)" << endl; }
template<class T> void g(T a) {
f(123);
h(a);
}
void f(int) { cout << "Function f(int)" << endl; }
void h(double) { cout << "Function h(double)" << endl; }
void i() {
extern void h(int);
g<int>(234);
}
void h(int) { cout << "Function h(int)" << endl; }
int main(void) {
i();
}
Run Code Online (Sandbox Code Playgroud)
它会打印什么?
我在这里修改了这个例子的IBM文档说它会打印:
Function f(double)
Function h(double)
Run Code Online (Sandbox Code Playgroud)
这个的基本原理是模板参数依赖的名称查找是在实例化之前执行的i(),所以它找到h(double) …
我有一个带有继承和shared_ptr来自 boost 库的简单代码。使用标准 c++20,代码可以正常编译。函数调用static_pointer_cast和dynamic_pointer_cast编译无需预先boost::命名空间——这些函数调用之所以有效,是因为 ADL(参数相关查找)。
但对于标准 c++17,代码将无法编译。我认为 ADL 没有实现,或者实现方式不同。但是,如果我添加using namespace std,代码就可以正常编译。我的问题是:与库的函数调用std有什么关系?boost
这是在线编译器,因此您可以通过注释行中和注释行来进行操作using namespace std;: https: //godbolt.org/z/cz8Md5Ezf
#include <iostream>
#include <boost/shared_ptr.hpp>
#include <boost/make_shared.hpp>
// using namespace std;
class Animal {
public:
Animal()
{}
virtual ~Animal()
{}
void speak()
{
std::cout << "I am an animal\n";
}
};
class Dog : public Animal {
public:
Dog()
{}
void bark()
{
std::cout << "Gheu --> ";
}
void …Run Code Online (Sandbox Code Playgroud) 查看n3092,在§6.5.4中,我们找到了基于范围的for循环的等价性.然后它继续说什么__begin和__end等于.它区分了数组和其他类型,我觉得这是多余的(也就是令人困惑).
它表示数组类型__begin和__end你所期望的:指向第一个的指针和指向一个结尾的指针.那么对于其他类型的,__begin并__end等于begin(__range)和end(__range),与ADL.命名空间std是关联的,以便在第24.6.5节中找到std::begin并std::end定义<iterator>.
但是,如果我们看的定义std::begin和std::end,他们是阵列以及容器类型都定义.并且数组版本与上面完全相同:指向第一个的指针,指向一个结尾的指针.
为什么需要将数组与其他类型区分开来,当为其他类型提供的定义同样适用时,查找std::begin和std::end?
为方便起见,有些删节报价:
§6.5.4基于范围的
for陈述- 如果_RangeT是一个数组类型,则begin-expr和end-expr分别是__range和__range + __bound,其中__bound是数组绑定的.如果_RangeT是未知大小的数组或不完整类型的数组,则程序格式错误.
- 否则,begin-expr和end-expr分别是begin(__ range)和end(__ range),其中begin和end通过参数依赖查找(3.4.2)查找.出于此名称查找的目的,名称空间std是关联的名称空间.
§24.6.5范围访问
Run Code Online (Sandbox Code Playgroud)template <class T, size_t N> T* begin(T (&array)[N]);返回:数组.
Run Code Online (Sandbox Code Playgroud)template <class T, size_t N> T* end(T (&array)[N]);返回:数组+ N.
当我尝试编译此代码时
// void foobar(int);
template <class T>
struct Foo {
void bar(T t) { foobar(t); };
};
void foobar(int);
template class Foo<int>;
Run Code Online (Sandbox Code Playgroud)
使用g ++ 4.8.2我收到以下错误消息
foo.cc: In instantiation of ‘void Foo<T>::bar(T) [with T = int]’:
foo.cc:10:16: required from here
foo.cc:5:27: error: ‘foobar’ was not declared in this scope, and no
declarations were found by argument-dependent lookup at
the point of instantiation [-fpermissive]
void bar(T t) { foobar(t); };
^
foo.cc:8:6: note: ‘void foobar(int)’ declared here, later in the translation unit …Run Code Online (Sandbox Code Playgroud)