Вызов перегруженного конструктора из списка инициализации конструктора - PullRequest
1 голос
/ 06 октября 2011

В приведенном ниже коде я намереваюсь вызвать один из двух перегруженных конструкторов для kap (класс opacity) в зависимости от того, какие аргументы передаются объекту класса material:

class opacity{
 private:
  int mode;
  double kap_const;
  double kappa_array[10][10];

 public:
  opacity(double constkap);  // picking the constructor sets the mode
  opacity(char* Datafile);
  double value(double T, double P); // will return a constant or interpolate
};

opacity::opacity(double constkap):mode(1){
  kap_const = constkap;
}

opacity::opacity(char* Datafile):mode(2){
  // read file into kappa_array...
}

class Matter {
 public:
  Matter(int i, double k, char* filename); // many more values are actually passed
  opacity kap;
  int x;  // dummy thing
  // more variables, call some functions
};

Matter::Matter(int i, double k, char * filename)
 :x(k>0? this->kap(x): this->kap(filename) ) {
  // ... rest of initialisation
 }

Это, однако, не работает:

test.cpp: In constructor 'Matter::Matter(int, double, char*)':
test.cpp:32:21: error: no match for call to '(opacity) (void*&)'
test.cpp:32:42: error: no match for call to '(opacity) (char*&)'
test.cpp:32:44: error: no matching function for call to 'opacity::opacity()'
test.cpp:32:44: note: candidates are:
test.cpp:20:1: note: opacity::opacity(char*)
test.cpp:20:1: note:   candidate expects 1 argument, 0 provided
test.cpp:16:1: note: opacity::opacity(double)
test.cpp:16:1: note:   candidate expects 1 argument, 0 provided
test.cpp:4:7: note: opacity::opacity(const opacity&)
test.cpp:4:7: note:   candidate expects 1 argument, 0 provided

Первое, что я попробовал,

Matter::Matter(int i, double k, char * filename)
 :kap(k>0? k: filename) {   // use k<0 as a flag to read from filename
  // ... rest of initialisation
}

также не удалось, потому что «результат троичного оператора всегда должен быть одного типа» по соображениям времени компиляции, как указано в аналогичном вопросе (хотя они там не были объяснены, кажется).

Теперь неэффективным решением будет также перегрузить конструктор Matter на основе аргументов, которые должен получить конструктор kap, но это (1) очень неэлегантно, тем более что конструктор Matter принимает много переменных и выполняет много действий (поэтому большая часть кода будет продублирована только для изменения части kap списка инициализации конструктора), и (2) это может выйти из-под контроля, если есть другой класс, используемый с Matter, который также имеет различные конструкторы: для M классов с N c'tors один заканчивается с N ^ M комбинациями ...

Будет ли у кого-то предложение или обходной путь? Заранее спасибо!

Ответы [ 4 ]

4 голосов
/ 06 октября 2011

Если у opacity есть конструктор копирования, это можно сделать в списке инициализации, избегая конструктора по умолчанию, но за счет копии:

  Matter::Matter(int i, double k, char * filename)
     :kap( ( 0 < k ) ? opacity(k) : opacity( filename ) ) { ... }
1 голос
/ 06 октября 2011

Чтобы избежать издержек при копировании, и, предполагая, что у вас есть компилятор C ++ 0x, вы можете дать непрозрачности конструктор перемещения , а статическая функция предоставит экземпляр opacity на основе вашей логики и инициализируетваш kap член с возвращенным временным opacity.

Возможно, вы захотите сделать kappa_array некоторый указатель типа auto_ptr<double>.Хотя, если эти данные используются в узком цикле, экономия от подвижности может быть сомнительной по сравнению со стоимостью локальности и разыменованием указателя.

opacity& get_opacity(double k, char * filename) {
    if(k > 0)
        return opacity(k);
    else
        return opacity(filename);
}

Matter::Mater(int i, double k, char * filename)
    : kap(get_opacity(k, filename) {
   //...
}

opacity::opacity(opacity&& other)
    : mode(other.mode),
      kap_const(other.kap_const),
      kappa_array(std::move(kappa_array)) { }

Пожалуйста, не проверяйте меня на этом, я 'Я довольно новый, с семантикой перемещения и ссылками на rvalue ...

1 голос
/ 06 октября 2011

Вам придется согласиться с добавлением конструктора по умолчанию к opacity (который, возможно, устанавливает режим на 0, чтобы указать недопустимый режим) и присвоить kap в теле конструктора.

Matter::Matter(int i, double k, char * filename) {
  if(k > 0)
    kap = opacity(k);
  else
    kap = opacity(filename);
}

Параметр k является значением времени выполнения.Невозможно сделать типы и результат перегрузки зависимыми от значений времени выполнения.

0 голосов
/ 06 октября 2011

Нельзя использовать троичный оператор для выбора переопределений функций, поскольку результат оператора имеет только один тип. В случае, когда разные ветви имеют разные типы, они будут приведены к типу результата или возникнет ошибка времени компиляции. Смотри http://en.wikipedia.org/wiki/%3F:#Result_type

Это не могло быть по-другому. Типы должны быть известны компилятору во время компиляции, но результат операции неизвестен до времени выполнения.

...