Использование члена класса в качестве аргумента по умолчанию для функции-члена
Есть ли другой способ, чем вручную перегрузить соответствующую функцию-член и вызвать первую перегрузку с членом в качестве аргумента?
Я пытаюсь что-то сделать в строках
class test
{
string t1="test";
testfun( string& val = this->t1 )
{ /* modify val somehow */ }
};
(Проверьте это: http://goo.gl/36p4CF)
В настоящее время, я думаю, нет никаких технических причин, почему это не должно работать.
- Есть ли решение, делающее это так, кроме перегрузки и установки параметра вручную?
- Почему это не работает, есть ли для этого техническая причина?
Ответы
Ответ 1
[dcl.fct.default]/8:
Ключевое слово this
не должно использоваться в аргументе по умолчанию для функции-члена.
Это частный случай общей проблемы: вы не можете ссылаться на другие параметры в аргументе по умолчанию для параметра. То есть.
void f(int a, int b = a) {}
Неправильно сформирован. И так будет
class A
{
int j;
};
void f(A* this, int i = this->j) {}
В основном это то, что компилятор преобразует функцию-член формы void f(int i = j) {}
в. Это связано с тем, что порядок оценки аргументов функции и постфиксное выражение (которое составляет аргумент объекта) не определено. [Dcl.fct.default]/9:
Аргументы по умолчанию оцениваются каждый раз при вызове функции. Порядок оценки аргументов функции не указан. Следовательно, параметры функции не должны использоваться по умолчанию аргумент, даже если они не оценены.
Ответ 2
Вы не сказали, чего хотите достичь. Я предполагаю, что вам нужно, чтобы каждый из ваших экземпляров реагировал определенным образом, в зависимости от определенной переменной класса.
Однако, если вам не требуется поведение каждого экземпляра, вы можете использовать статические переменные. Следующие работы:
#include <iostream>
using namespace std;
struct test {
static string t1;
void say(const string &val=t1){
cout << val << "!" << endl;
}
};
string test::t1;
int main() {
cout << "Hello World" << endl;
test::t1 = string("asd");
test a;
a.say();
a.say("bla");
test::t1 = string("blahblah");
a.say();
return 0;
}
... что означает, что все объекты класса test
будут использовать статическую строку t1
в качестве значения по умолчанию.
Вы можете немного "взломать" и использовать это как уродливый страж:
void say(const string &val=t1){
if (&val == &t1) {
// They are using the default value, so act as you want
} else {
// they are providing a value
}
}
Ответ 3
Есть ли решение, делающее это таким образом, кроме перегрузки и установки параметра вручную?
Нет, вам понадобится перегрузка, если вы хотите, чтобы аргумент по умолчанию зависел от другого параметра, включая this
. Хотя в этом случае это не имеет смысла, поскольку это конструктор, а t1
не существует до его вызова.
Почему это не работает, есть ли для этого техническая причина?
Поскольку порядок оценки аргументов функции не указан. Чтобы разрешить значения параметров в аргументах по умолчанию, вам понадобится гораздо более сложные правила, чтобы гарантировать, что каждый параметр был инициализирован перед использованием.