我试图检测何时调用显式构造函数调用而不是隐式构造函数调用。
假设我们有一个班级Foo
:
class Foo{
public:
Foo(int _val) : val(_val){};
private:
int val;
}
void bar(Foo f){
...
}
我们可以像以下一样打电话:
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;
}
但正如预期的那样,它返回"不能重载",因为函数签名是不明确的。
最终结果应该是:
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 ++中实现这一点。如果不是,那就没问题了。
答案 0 :(得分:3)
甚至可以在C ++中执行此操作吗?
没有
正如您所看到的那样,超载的不确定性是一个问题,这使您无法知道隐式构造函数是被调用还是显式构造函数。
可以假设在你的情况中,通过密切关注显式构造函数所需的副本(与隐式构造函数相比),可以知道调用了哪个构造函数,但这并不是那么可靠,因为好的编译器可以利用Copy Elision并绕过复制操作。
因此,如果我们依赖于我们的复制假设来确定是否调用了显式构造函数,那么我们可能会收到假阴性,以防副本实际被删除。
通常,允许复制构造函数被删除,它们应该不有副作用。
答案 1 :(得分:2)
所以我想也许可以找到一种解决方法来检测显式调用与隐式调用,如下所示:
不,这是不可能的。如果这纯粹是出于好奇,那么你有答案。如果你正在尝试克服真正的问题,你可能想发布真正的问题。
答案 2 :(得分:2)
这很简单,但解决方案是在被调用的函数中,而不是在您正在创建的对象中。
void bar(Foo&) { ... }
void bar(Foo&&) { ... }
Foo f(10);
bar(f); // calls the first one
bar(10); // calls the second one