调用命名函数
<...>如果表达式E是主表达式,则按照函数调用的正常规则(可能涉及ADL)查找名称.此查找找到的函数声明(由于查找的工作方式):<...>
b)某些类T的所有成员函数,在这种情况下,如果它在范围内并且引用T,则*将其用作隐含对象参数.否则(如果它不在范围内或者不指向T),则使用类型为T的伪对象作为隐含对象参数,如果重载决策随后选择非静态成员函数,则程序格式错误.
似乎第二种情况是关于func(arg)方法内部的调用.何时可能this不在此类案件的范围内?
或者它不只是谈论func(arg)方法中的类似东西?
使用命名参数调用 aDictionary的Add()方法在 F# 中有效。
let d = Dictionary<string, obj>()
d.Add(key = "five", value = 5)
let d2= Dictionary<obj, obj>()
d2.Add(key = "five", value = 5)
d2.Add(key = 5, value = 5)
Run Code Online (Sandbox Code Playgroud)
在 Polly 的Contextclass 中,有一个类似的Add()方法,有 2 个重载:
Add(key: obj, value: obj) : unit
Add(key: string, value: obj) : unit
Run Code Online (Sandbox Code Playgroud)
我可以通过以下所有方式使用它:
let c = Polly.Context()
c.Add("five", 5)
c.Add(5, 5)
c.Add(key = 5, value = 5)
Run Code Online (Sandbox Code Playgroud)
但不是这样,它说它无法在重载之间解析并且需要类型注释。
c.Add(key = "five", value = 5)
Run Code Online (Sandbox Code Playgroud)
为什么会这样,我该如何解决?
我认为在嵌套命名空间中,任何属于父(或全局)命名空间的内容都被同等考虑用于重载解析,但此示例似乎另有说明。
这工作正常:
#include <iostream>
void foo(int) { std::cout << "int\n"; }
void foo(float) { std::cout << "float\n"; }
namespace NS {
void bar() {
foo(0);
}
}
int main() {
NS::bar();
}
Run Code Online (Sandbox Code Playgroud)
调用foo(0)匹配,foo(int)因为它是一个更好的匹配,一切都按预期工作。但是,如果我将 的声明移动foo(float)到命名空间中:
#include <iostream>
void foo(int) { std::cout << "int\n"; }
namespace NS {
void foo(float) { std::cout << "float\n"; }
void bar() {
foo(0);
}
}
int main() {
NS::bar();
}
Run Code Online (Sandbox Code Playgroud)
对foo(0)现在的呼吁foo(float)!
我已经搜索过https://en.cppreference.com/w/cpp/language/overload_resolution和许多其他此类页面,以找到解释这一点的规则,但我似乎错过了它。有人可以解释一下许多复杂的重载解析规则中的哪一个会导致这种情况,还是其他原因?
编辑
我刚刚发现它更奇怪。即使 …
在这段代码中,为什么编译器无法从静态上下文引用具有 varargs 参数的方法。
private static void doSomething(int... nums) {
System.out.println("1");
}
private void doSomething(int num1, int num2) {
System.out.println("2");
}
public static void main(String[] args) {
doSomething(1,2);
}
Run Code Online (Sandbox Code Playgroud)
JDK 17 正在抱怨Cannot make a static reference to the non-static method doSomething(int, int) 。这是一个错误还是我不知道的其他功能。
JDK 8 和 JDK 11 不要抱怨它!
为什么 C++ 选择原始类型重载匹配而不是“更好”的匹配初始值设定项列表?
#include <vector>
void foo([[maybe_unused]] int i) {}
void foo([[maybe_unused]] const std::vector<int>& v) {}
int main() {
foo(0);
foo({1,2,3});
foo({0}); // calls foo(int) and issues a warning,
// rather than what seems like the "better"
// match foo(vector).. why?
}
Run Code Online (Sandbox Code Playgroud)
<source>:10:9: warning: braces around scalar initializer [-Wbraced-scalar-init]
foo({0}); // calls foo(int) and issues a warning,
^~~
Run Code Online (Sandbox Code Playgroud)
也许是“令人惊讶”的结果,因为编译器选择了随后发出诊断的选项?
使用 Clang 14
c++ overloading initializer-list language-lawyer overload-resolution
考虑这个例子:
\nint foo(void);\nextern "C" int foo(void);\n\nint main()\n{\n return foo();\n}\nRun Code Online (Sandbox Code Playgroud)\n它出错了:
\n$ g++ -c main.cpp\nmain.cpp:2:16: error: conflicting declaration of \xe2\x80\x98int foo()\xe2\x80\x99 with \xe2\x80\x98C\xe2\x80\x99 linkage\n 2 | extern "C" int foo(void);\n | ^~~\nmain.cpp:1:5: note: previous declaration with \xe2\x80\x98C++\xe2\x80\x99 linkage\n 1 | int foo(void);\n | ^~~\nRun Code Online (Sandbox Code Playgroud)\n这完全没问题。
\n但是让我们交换前两行:
\nextern "C" int foo(void);\nint foo(void);\n\nint main()\n{\n return foo();\n}\nRun Code Online (Sandbox Code Playgroud)\n现在它编译时没有任何错误,\n但是选择了 C 链接,即使\n最后找到了 C++ 链接。
\n问题:
\n我正在尝试设计一个包装器来使用一些特殊逻辑来处理算术参数。
https://godbolt.org/z/zG959e5Pz
#include <stdio.h>
template <class T>
struct wrapper {
wrapper(const T& o): value(o) {}
T value;
};
void func(wrapper<int> a) {
printf("int: %d\n", a.value);
}
int main () {
func(1); // int: 1
func(1.0); // int: 1
}
Run Code Online (Sandbox Code Playgroud)
但是,当我声明 的重载函数时func,我遇到了编译错误。编译器似乎无法选择具体的重载函数。
#include <stdio.h>
template <class T>
struct wrapper {
wrapper(const T& o): value(o) {}
T value;
};
void func(wrapper<int> a) {
printf("int: %d\n", a.value);
}
void func(wrapper<double> a) {
printf("double: %.2f\n", a.value);
}
int main () {
func(1); …Run Code Online (Sandbox Code Playgroud) 我正在学习c ++并使用C++ Primer.请考虑以下练习14.46:
class Complex {
Complex(double);
// ...
};
class LongDouble {
friend LongDouble operator+(LongDouble&, int); // (1)
public:
LongDouble(int);
operator double();
LongDouble operator+(const Complex &); // (2)
// ...
};
LongDouble operator+(const LongDouble &, double); // (3)
LongDouble ld(16.08);
double res = ld + 15.05; // which operator+ ?
Run Code Online (Sandbox Code Playgroud)
当我用gcc 4.5编译上面的程序时,我得到了
14_46.cpp:60:21: error: ambiguous overload for ‘operator+’ in ‘ld + 1.5050000000000000710542735760100185871124267578125e+1’
14_46.cpp:60:21: note: candidates are: operator+(double, double) <built-in>
14_46.cpp:35:5: note: LongDouble LongDouble::operator+(const Complex&)
14_46.cpp:45:1: note: LongDouble operator+(const LongDouble&, …Run Code Online (Sandbox Code Playgroud) 我试图理解,为什么GCC f(char, A<C, 5> &var)在下面的代码中选择重载解析:
template <class C, int N> struct A { };
template <class C> struct A<C, 8> { static_assert(sizeof(C) > 8, "Assertion in A<C,8>"); };
template <class C> struct A<C, 5> { static_assert(sizeof(C) < 8, "Assertion in A<C,5>"); operator A<C,8>&(); };
template <class C> void f(double, A<C,8> &var);
template <class C> void f(char, A<C,5> &var);
int main(void)
{
A<int, 5> a;
f(4., a);
}
Run Code Online (Sandbox Code Playgroud)
有两种可用的重载:
template <class C> void f(double, A<C,8> &var);
Run Code Online (Sandbox Code Playgroud)
4.完全匹配double(不需要隐式转换),但第二个参数需要用户定义的转换.所以这个过载: …
在以下程序中,应选择哪个(如果有)转换功能,为什么?
int r;
struct B {};
struct D : B {};
struct S {
D d;
operator D&(){r=1; return d;} // #1
operator B&(){r=2; return d;} // #2
};
int main() {
S s;
B& b = s;
return r;
}
Run Code Online (Sandbox Code Playgroud)
gcc和clang选择均选择转换功能#2。但为什么?
标准说:
(1)在[dcl.init.ref]中指定的条件下,可以将引用直接绑定到将转换函数应用于初始化程序表达式的结果。重载解析用于选择要调用的转换函数。假设“对cv1 T的引用”是要初始化的引用的类型,而“ cv S”是初始化程序表达式的类型,其中S为类类型,则按以下方式选择候选函数:
(1.1)-考虑S的转换函数及其基类。那些未隐藏在S中且产生类型“对cv2 T2的左值引用”(初始化对函数的左值引用或右值引用时)或“ cv2 T2”或“对cv2 T2的右值引用”的非显式转换函数将右值引用或左值引用初始化为函数),其中“ cv1 T”与“ cv2 T2”的引用兼容)是候选函数。对于直接初始化,未隐藏在S中的那些显式转换函数会产生类型“对cv2 T2的左值引用”(初始化对函数的左值引用或右值引用)或“对cv2 T2的右值引用”(当初始化对函数的右值引用或左值引用),
(2)参数列表有一个参数,它是初始化器表达式。[?注:此参数将与转换函数的隐式对象参数进行比较。-?尾注?]
这里我们有两个候选函数#1和#2。两者都可行-如果删除其中之一,程序仍会编译。这两个转换函数仅采用隐式参数,并且具有相同的cv和ref限定。因此,没有一个应该是最可行的,并且该程序也不应编译。为什么编译?
c++ language-lawyer overload-resolution implicit-conversion reference-binding