如何区分 C++ 中的 implicit/explicit 构造函数调用?
How to differentiate implicit/explicit constructor calls in C++?
我正在尝试检测何时调用显式构造函数调用与隐式构造函数调用。
假设我们有一个 class Foo
:
class Foo{
public:
Foo(int _val) : val(_val){};
private:
int val;
}
void bar(Foo f){
...
}
我们可以这样调用 bar:
Foo f(10);
bar(f);
或喜欢:
bar(10); // implicit initialization
现在,我知道如果我们明确构造函数:
class Foo{
public:
explicit Foo(int _val) : val(_val){};
private:
int val;
}
然后我们可以得到这个错误:
bar(10); // ERROR! implicit initialization not allowed.
所以我想也许可以有一种变通方法来检测显式调用与隐式调用,如下所示:
class Foo{
public:
explicit Foo(int _val) : val(_val){}; // calling Foo f(10); bar(f);
Foo(int _val) : val(_val){}; // calling bar(10);
private:
int val;
}
但正如预期的那样,它 returns "cannot be overloaded",因为函数签名不明确。
最终结果应该是这样的:
class Foo{
public:
explicit Foo(int _val) : val(_val), flag(true) {}; // calling Foo f(10); bar(f);
Foo(int _val) : val(_val), flag(false) {}; // calling bar(10);
private:
int val;
bool flag;
}
void bar(Foo f){
std::cout << "f's flag set to : " << f.flag << std::endl;
}
Foo f(10);
bar(f); // f's flag set to : 1
bar(10); // f's flag set to : 0
但很明显,由于上述尝试是徒劳的,而且我也没有更好的主意,我想知道 是否有可能在 C++ 中做到这一点。如果不是,那也没关系。
So I thought perhaps there could be a workaround to detect an explicit call vs. implicit, like this:
不,这不可能。如果这纯粹是出于好奇,那么你就有了答案。如果您正在尝试克服真正的问题,您可能想要 post 真正的问题。
it is even possible to do this in C++?
没有.
如您所见,重载歧义是一个问题,这使您无法知道调用的是隐式构造函数还是显式构造函数。
人们可能会假设 在您的情况下 可以通过留意显式构造函数所需的副本来知道调用了哪个构造函数(与隐式的),但这并不是那么可靠,因为一个好的编译器可以利用 Copy Elision 并绕过复制操作。
因此,如果我们依靠我们的复制假设来确定显式构造函数是否被调用,我们可能会收到假阴性,以防复制实际上被删除。
一般来说,复制构造函数是允许省略的,它们应该不会有副作用。
这很简单,但解决方案是在被调用的函数中,而不是在您正在创建的对象中。
void bar(Foo&) { ... }
void bar(Foo&&) { ... }
Foo f(10);
bar(f); // calls the first one
bar(10); // calls the second one
我正在尝试检测何时调用显式构造函数调用与隐式构造函数调用。
假设我们有一个 class Foo
:
class Foo{
public:
Foo(int _val) : val(_val){};
private:
int val;
}
void bar(Foo f){
...
}
我们可以这样调用 bar:
Foo f(10);
bar(f);
或喜欢:
bar(10); // implicit initialization
现在,我知道如果我们明确构造函数:
class Foo{
public:
explicit Foo(int _val) : val(_val){};
private:
int val;
}
然后我们可以得到这个错误:
bar(10); // ERROR! implicit initialization not allowed.
所以我想也许可以有一种变通方法来检测显式调用与隐式调用,如下所示:
class Foo{
public:
explicit Foo(int _val) : val(_val){}; // calling Foo f(10); bar(f);
Foo(int _val) : val(_val){}; // calling bar(10);
private:
int val;
}
但正如预期的那样,它 returns "cannot be overloaded",因为函数签名不明确。
最终结果应该是这样的:
class Foo{
public:
explicit Foo(int _val) : val(_val), flag(true) {}; // calling Foo f(10); bar(f);
Foo(int _val) : val(_val), flag(false) {}; // calling bar(10);
private:
int val;
bool flag;
}
void bar(Foo f){
std::cout << "f's flag set to : " << f.flag << std::endl;
}
Foo f(10);
bar(f); // f's flag set to : 1
bar(10); // f's flag set to : 0
但很明显,由于上述尝试是徒劳的,而且我也没有更好的主意,我想知道 是否有可能在 C++ 中做到这一点。如果不是,那也没关系。
So I thought perhaps there could be a workaround to detect an explicit call vs. implicit, like this:
不,这不可能。如果这纯粹是出于好奇,那么你就有了答案。如果您正在尝试克服真正的问题,您可能想要 post 真正的问题。
it is even possible to do this in C++?
没有.
如您所见,重载歧义是一个问题,这使您无法知道调用的是隐式构造函数还是显式构造函数。
人们可能会假设 在您的情况下 可以通过留意显式构造函数所需的副本来知道调用了哪个构造函数(与隐式的),但这并不是那么可靠,因为一个好的编译器可以利用 Copy Elision 并绕过复制操作。
因此,如果我们依靠我们的复制假设来确定显式构造函数是否被调用,我们可能会收到假阴性,以防复制实际上被删除。
一般来说,复制构造函数是允许省略的,它们应该不会有副作用。
这很简单,但解决方案是在被调用的函数中,而不是在您正在创建的对象中。
void bar(Foo&) { ... }
void bar(Foo&&) { ... }
Foo f(10);
bar(f); // calls the first one
bar(10); // calls the second one