如何区分C ++中的隐式/显式构造函数调用?

时间:2017-09-15 17:19:08

标签: c++ class oop constructor explicit

我试图检测何时调用显式构造函数调用而不是隐式构造函数调用。

假设我们有一个班级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 ++中实现这一点。如果不是,那就没问题了。

3 个答案:

答案 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