2017-02-16 12 views
2

Рассмотрите класс с удаленным конструктором по умолчанию (мой фактический класс намного сложнее, а конструктор по умолчанию удален неявно из-за того, что один из его членов имеет удаленный конструктор по умолчанию). Я хотел бы создать экземпляр класса с одним из его конструкторов на основе значения некоторого ввода, а затем сделать «кучу вещей». В следующем коде показаны два способа, по которым это невозможно сделать по причинам, указанным в комментариях к коду, но дает представление о том, чего я пытаюсь достичь.Условно создать экземпляр класса с удаленным конструктором по умолчанию

#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 
} 

Один очевидный способ сделать это было бы, чтобы переместить «кучу вещей» внутри каждую часть if блока, но это привело бы к большому количеству повторяющегося кода, который я хочу, чтобы избежать.

Другим очевидным способом было бы создать функцию для выполнения «кучки вещей» и называть это в каждой части блока if, но для этого требуется определенное количество рефакторинга, и вызов функции может стать довольно уродливым, если представляют собой большое количество переменных, которые необходимо передать ему.

Итак, мой вопрос: есть ли какой-то способ условно создать экземпляр класса и иметь его в окружении?

ответ

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

Хотя решение juanchopanza более просто отвечает на мой вопрос, я в конечном итоге использовал это решение как вектор ' v', который генерируется нетривиально и только должен быть сгенерирован для этого выбора конструктора, не приводит к загрязнению окружающей области. –

4

Вы можете создать его экземпляр с помощью условного оператора:

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

и так далее.

0

Вы можете сделать бесплатную функцию (возможно, статическую в A ::, R Sahu в пользу свободной функции) верните соответствующий a.

A a = buildA(yes_no); 

buildA будет

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

и так далее.

+1

Не нужно загрязнять 'A' дополнительной логикой. Лучше иметь его как функцию, не являющуюся членом. –

0

Здесь вы можете использовать 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}).

Или, как предложили другие, извлеките логику создания объекта в отдельную функцию, где вы можете возвращать объекты из блоков if в зависимости от выполнения условий yes_no.

+0

С C++ 14, учитывая использование '= make_unique (args)' вместо '.reset (new A (args))' –