有条件地实例化具有已删除默认构造函数的 class

Conditionally instantiate a class that has a deleted default constructor

考虑带有已删除默认构造函数的 class(我的实际 class 要复杂得多,并且由于其成员之一具有已删除的默认构造函数,默认构造函数被隐式删除)。我想根据某些输入的值用它的构造函数之一实例化我的 class,然后执行 "a bunch of things"。 以下代码显示了由于代码注释中所述的原因而无法完成的两种方法,但给出了我要实现的目标的想法。

#include <vector>
class A {
    bool m_with_v;
    int m_i;
    std::vector<double> m_v;
public:
    A() = delete;
    A(int i) : m_i(i), m_with_v(false) {}
    A(int i, std::vector<double> v) : m_i(i), m_v(v), m_with_v(true) {}
    auto do_stuff() { /* do stuff depending on m_with_v */ };
};

int main(int argc, char* argv[])
{
    bool yes_no;
    /* Obtain a value for yes_no from argv */

    A a; // the default constructor of "A" cannot be referenced -- it is a deleted function
    if (yes_no)
        a = A(1);
    else {
        std::vector<double> v{ 1,2,3 };
        a = A(1, v);
    }
    a.do_stuff();
    // do a bunch more things

    if (yes_no)
        A b(1);
    else {
        std::vector<double> v{ 1,2,3 };
        A b(1, v);
    }
    b.do_stuff(); // identifier "b" is undefined, i.e. it's gone out of scope
    // do a bunch more things
}

一个明显的方法是将 "bunch of things" 移动到 if 块的每个部分内,但这会导致大量重复代码,我想避免这种情况。

另一个明显的方法是创建一个函数来执行 "bunch of things" 并在 if 块的每个部分调用它,但这需要一定量的重构并且函数调用可以如果有大量变量需要传递给它,就会变得相当丑陋。

所以,我的问题是:是否有某种方法可以有条件地实例化我的 class 并使其在周围范围内可用?

您可以使用条件运算符实例化它:

A a = yes_no ? A(1) : A(1, {1,2,3});
a.do_stuff();

等等。

你可以做一个自由函数(也许在A::中是静态的,R萨胡赞成自由函数)return一个合适的a.

A a = buildA(yes_no);

buildA 将是

A buildA(bool yes_no){
   if (yes_no) 
       return A(1);

等等。

你可以考虑在这里使用 unique_ptr<A>。这样你就可以推迟实际的对象创建并在你需要的条件块中创建一个合适的实例。 例如:

std::unique_ptr<A> ptrA;
if (yes_no)
{
    ptrA.reset(new A(1));
}
else
{
    ptrA.reset(new A(1,{1,2,3}));
}

根据您使用的实际 c++ 版本,您可能希望使用 std::make_unique 而不是 reset 方法(自 C++14 起可用)。在这种情况下,您将输入 ptrA = std::make_unique<A>(1);.

另一种选择是使用三元运算符 A a = (yes_no) ? A(1) : A(1, {1, 2, 3})

或者按照其他人的建议,将对象创建逻辑提取到一个单独的函数中,您可以根据 yes_no 条件的满足从 if 块中提取 return 个对象。

auto a = [&]{
    if (yes_no) {
        return A(1);
    } else {
        std::vector<double> v{ 1,2,3 };
        return A(1, v);
    }
}();
a.do_stuff();