我尝试使用重载的运算符==()在向量中找到一个元素.但是,如果type1在以下代码中使用,则输出为1和0(未找到).使用type2给出1和1.环境是Xubuntu 12.04和g ++版本4.6.3.
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
typedef pair<string, int> type1;
struct type2: public type1 {};
#define TYPE type1
bool operator== (const TYPE& lhs, const TYPE& rhs) {
return lhs.first == rhs.first;
}
int main()
{
vector<TYPE> vec;
TYPE v1, v2;
v1.first = "abc"; v1.second = 1; vec.push_back(v1);
v2.first = "abc"; v2.second = 2;
cout << (v1 == v2) << endl;
cout << (find(vec.begin(), vec.end(), v2) != vec.end()) << endl;
}
Run Code Online (Sandbox Code Playgroud) c++ operator-overloading overload-resolution name-lookup argument-dependent-lookup
在下面的C++示例代码中,GCC 6和Clang 3.8不同意正确的行为:
这个人为的例子"有效" - 就像GCC 中的test()函数返回一样o.p.在clang中,它调用(undefined)函数get<int, int, float, double>:
template<typename ...Args>
class obj {
bool p = false;
template<typename T, typename... Args2>
friend T get(const obj<Args2...> &o) { return o.p; }
};
template<typename T, typename... Args>
T get(const obj<Args...> &o);
bool test(const obj<int, float, double> &a) {
return get<int>(a);
}
Run Code Online (Sandbox Code Playgroud)
将相同的代码放在命名空间中会导致GCC执行与clang相同的操作.
namespace ns {
template<typename ...Args>
class obj {
bool p = false;
template<typename T, typename... Args2>
friend T get(const obj<Args2...> &o) { …Run Code Online (Sandbox Code Playgroud) 我正在阅读这篇博客文章部分,并尝试使用提供的代码段.
namespace N {
// 2
class A {
friend void f(A) {} // 1
};
}
Run Code Online (Sandbox Code Playgroud)
如果我理解正确,那么定义// 1将注入名称f所在// 2的位置.但是它只能通过参数依赖查找来获得.精细.
帖子里有一句引起我注意的句子:
7.3.1.2/3命名空间成员定义[namespace.memdef] p3
首先在名称空间中声明的每个名称都是该名称空间的成员.如果非本地类中的友元声明首先声明了类,函数,类模板或函数模板,则该友元是最内层封闭命名空间的成员.友元声明本身不会使名称对非限定查找(3.4.1)或限定查找(3.4.3)可见.
请注意,没有任何地方声明,友元声明引入的名称必须与声明和/或定义的类的名称有任何特定的关系,或者与该类的任何特定关系(就此而言).
由此,我认为以下代码段是有效的:
namespace N {
struct A {
};
struct B {
friend void f(A) {
}
};
int main() {
N::A a;
f(a);
}
Run Code Online (Sandbox Code Playgroud)
但它被GCC7和Clang 4都拒绝了.
t.cpp:19:3:错误:在此范围内未声明'f'
有趣的是,当我尝试f使用N::B对象调用时,我收到以下错误:
t.cpp:12:6:错误:无法将'b'从'N :: B'转换为'N :: A'
所以这是我的问题:
不f(A)应该通过ADL检测到?由于这两个类都在命名空间中,我不明白为什么会失败.我查看了标准关于朋友的部分,但未找到相关部分.
我想知道f(A)注入了哪个范围,因为当我尝试通过调用给出错误的参数类型时,GCC能够找到它f(B).
正确使用std :: swap是:
using std::swap;
swap(a,b);
Run Code Online (Sandbox Code Playgroud)
它有点冗长,但它确保如果a,b有更好的交换定义它将被选中.
所以现在我的问题是为什么std::swap没有使用这种技术实现,所以用户代码只需要调用std::swap?
所以这样的事情(noexcept为了简洁而忽略和约束):
namespace std {
namespace internal {
template <class T> // normal swap implementation
void swap(T& a, T& b) { // not intended to be called directly
T tmp = std::move(a);
a = std::move(b);
b = std::move(tmp);
}
}
template <class T>
void swap(T& a, T& b) {
using internal::swap;
swap(a,b);
}
}
Run Code Online (Sandbox Code Playgroud) c++ template-function argument-dependent-lookup customization-point
我无意在实际代码中使用它.我承诺.
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不考虑的命名空间中定义?
提前致谢.
我正在查看关于参数依赖查找的维基百科条目,并且(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的理解是正确的吗?)
以下代码使用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
下面的程序在 C++20 中编译得很好:
#include <memory>
struct A{ virtual ~A() = default; };
struct B: A {};
int main()
{
std::shared_ptr<A> p = std::make_shared<B>();
auto x = dynamic_pointer_cast<A>(p);
}
Run Code Online (Sandbox Code Playgroud)
但是在 C++17 中它会产生一个错误:
<source>: In function 'int main()':
<source>:9:14: error: 'dynamic_pointer_cast' was not declared in this scope; did you mean 'std::dynamic_pointer_cast'?
9 | auto x = dynamic_pointer_cast<A>(p);
| ^~~~~~~~~~~~~~~~~~~~
| std::dynamic_pointer_cast
In file included from /opt/compiler-explorer/gcc-11.1.0/include/c++/11.1.0/memory:77,
from <source>:1:
Run Code Online (Sandbox Code Playgroud)
你能告诉我在 C++20 中有什么改变使它工作吗?
否则,如果 Ranges::disable_sized_range<std::remove_cv_t<T>> 为 false,则 size(t) 转换为其衰减类型,并且转换后的表达式有效且具有类似整数的类型,其中重载解析通过以下命令执行以下候选人:
void size(auto&) = delete;void size(const auto&) = delete;1
class Test {
friend size_t size(/*const*/ Test&) {
return 0;
}
};
int main() {
std::ranges::size(Test{});
// no matching function error when adding the `const` qualifier
}
Run Code Online (Sandbox Code Playgroud)
https://godbolt.org/z/79e5vrKrT
一般来说,方法size不需要像std::size.
为什么会有这样的限制呢std::ranges::size?(好像只有非会员版才能执行。)