考虑以下代码:
struct A
{
void foo() const
{
std::cout << "const" << std::endl;
}
private:
void foo()
{
std::cout << "non - const" << std::endl;
}
};
int main()
{
A a;
a.foo();
}
Run Code Online (Sandbox Code Playgroud)
编译器错误是:
错误:'void A :: foo()'是私有的.
但是当我删除私有它时它才起作用.为什么在非const的私有时不调用public const方法?
换句话说,为什么在访问控制之前会出现重载决策?这很奇怪.你认为它是一致的吗?我的代码工作,然后我添加一个方法,我的工作代码根本不编译.
我有这门课
public class Overloaded
{
public void ComplexOverloadResolution(params string[] something)
{
Console.WriteLine("Normal Winner");
}
public void ComplexOverloadResolution<M>(M something)
{
Console.WriteLine("Confused");
}
}
Run Code Online (Sandbox Code Playgroud)
如果我这样称呼它:
var blah = new Overloaded();
blah.ComplexOverloadResolution("Which wins?");
Run Code Online (Sandbox Code Playgroud)
它写入Normal Winner
控制台.
但是,如果我添加另一种方法:
public void ComplexOverloadResolution(string something, object somethingElse = null)
{
Console.WriteLine("Added Later");
}
Run Code Online (Sandbox Code Playgroud)
我收到以下错误:
以下方法或属性之间的调用不明确:>'
Overloaded.ComplexOverloadResolution(params string[])
'和'Overloaded.ComplexOverloadResolution<string>(string)
'
我可以理解,添加一个方法可能会引入一个电话不确定性,但它的两种方法之间的不确定性已经存在的(params string[])
和<string>(string)
!很明显,模糊性中涉及的两种方法都不是新添加的方法,因为第一种是params,第二种是泛型.
这是一个错误吗?该规范的哪一部分说应该是这种情况?
我正在尝试理解重载解析方法.
为什么这个含糊不清:
void func(double, int, int, double) {}
void func(int, double, double, double) {}
void main()
{
func(1, 2, 3, 4);
}
Run Code Online (Sandbox Code Playgroud)
但这不是?
void func(int, int, int, double) {}
void func(int, double, double, double) {}
void main()
{
func(1, 2, 3, 4);
}
Run Code Online (Sandbox Code Playgroud)
在第一种情况下,有2个精确参数匹配,2个转换针对1个完全匹配和3个转换,在第二种情况下,有3个完全匹配,1个转换针对1个完全匹配和3个转换.
那么为什么一个模棱两可而一个不是?这里的逻辑是什么?
为什么doSomething
编译器会先调用前两个,但是在列表中使用两个元素会导致调用不明确?
#include <vector>
#include <string>
void doSomething(const std::vector<std::string>& data) {}
void doSomething(const std::vector<int>& data) {}
int main(int argc, char *argv[])
{
doSomething({"hello"}); // OK
doSomething({"hello", "stack", "overflow"}); // OK
doSomething({"hello", "stack"}); // C2668 'doSomething': ambiguous call
return 0;
}
Run Code Online (Sandbox Code Playgroud) 假设我正在编写一个函数来打印字符串的长度:
template <size_t N>
void foo(const char (&s)[N]) {
std::cout << "array, size=" << N-1 << std::endl;
}
foo("hello") // prints array, size=5
Run Code Online (Sandbox Code Playgroud)
现在我想扩展foo
以支持非数组:
void foo(const char* s) {
std::cout << "raw, size=" << strlen(s) << std::endl;
}
Run Code Online (Sandbox Code Playgroud)
但事实证明,这破坏了我原来的预期用途:
foo("hello") // now prints raw, size=5
Run Code Online (Sandbox Code Playgroud)
为什么?这不需要数组到指针的转换,而模板是完全匹配的吗?有没有办法确保我的数组函数被调用?
前段时间我读了一篇文章解释了参数依赖查找的几个缺陷,但我再也找不到了.它是关于获取您不应该访问的东西或类似的东西.所以我想我会在这里问:ADL的缺陷是什么?
c++ namespaces overload-resolution argument-dependent-lookup
我写了这两个重载:
int func(int, int) {
return 1;
}
int func(double, double) {
return 2;
}
Run Code Online (Sandbox Code Playgroud)
当我使用明显的两个调用方案(即func(1, 1)
and )调用它们时,分别调用func(1.0, 1.0)
了第一个和第二个重载函数,并且当我尝试调用func(1, 1.0)
它时会出现错误,但是当我将1
a强制转换为 a 时long long
,我不会得到一个错误,第二个重载就是被调用的那个。
#include <iostream>
int main()
{
std::cout << func(1, 1); // outputs 1.
std::cout << func(1.0, 1.0); // outputs 2.
// std::cout << func(1, 1.0); // erroneous.
std::cout << func((long long)1, 1.0); // outputs 2.
}
Run Code Online (Sandbox Code Playgroud)
为什么会这样?起初,我认为这是因为一些提升,但我尝试了带有两个浮点数的第三次重载,但我无法通过调用它来调用它像func((int)1, 1.0f)
. 我不知道为什么会不一样,也不知道为什么在long long
传递a 时会调用第二个重载。
考虑以下代码:
#include <iostream>
#include <string>
// void f(const char *) { std::cout << "const char *"; } // <-- comment on purpose
void f(const std::string &) { std::cout << "const std::string &"; }
void f(const void *) { std::cout << "const void *"; }
int main()
{
f("hello");
std::cout << std::endl;
}
Run Code Online (Sandbox Code Playgroud)
我编译了这个程序g++ (Ubuntu 6.5.0-1ubuntu1~16.04) 6.5.0 20181026
:
$ g++ -std=c++11 strings_1.cpp -Wall
$ ./a.out
const void *
Run Code Online (Sandbox Code Playgroud)
请注意,注释是为了测试而存在,否则编译器使用f(const char *)
.
那么,为什么编译器会f(const void*)
接管f(const std::string …
c++ overloading stdstring string-literals overload-resolution
这个完整的C#程序说明了这个问题:
public abstract class Executor<T>
{
public abstract void Execute(T item);
}
class StringExecutor : Executor<string>
{
public void Execute(object item)
{
// why does this method call back into itself instead of binding
// to the more specific "string" overload.
this.Execute((string)item);
}
public override void Execute(string item) { }
}
class Program
{
static void Main(string[] args)
{
object item = "value";
new StringExecutor()
// stack overflow
.Execute(item);
}
}
Run Code Online (Sandbox Code Playgroud)
我遇到了一个StackOverlowException,我追溯到这个调用模式,我试图将调用转发给更具体的重载.令我惊讶的是,调用并没有选择更具体的重载,而是回调自身.它显然与基类型是通用的有关,但我不明白为什么它不会选择执行(字符串)重载.
有没有人对此有任何见解?
上面的代码被简化为显示模式,实际结构有点复杂,但问题是一样的.
#include <iostream>
using namespace std;
template<typename T>
void f(T&&) { cout << "f(T&&)" << endl; }
template<typename T>
void f(const T&&) { cout << "f(const T&&)" << endl; }
struct A {};
const A g1() { return {}; }
const int g2() { return {}; }
int main()
{
f(g1()); // outputs "f(const T&&)" as expected.
f(g2()); // outputs "f(T&&)" not as expected.
}
Run Code Online (Sandbox Code Playgroud)
问题描述嵌入在代码中.我的编译器是clang 5.0
.
我只是好奇:
在这种情况下,为什么C++会以不同方式处理内置类型和自定义类型?