Альтернативы использованию значения атрибута класса в качестве параметра метода по умолчанию? - PullRequest
4 голосов
/ 23 февраля 2012

Я хочу добиться чего-то подобного:

class C
{
    int m_nVal;
public:
    C(int nVal) : m_nVal(nVal){}            

    void foo(int nVal = m_nVal)
    {
         // use nVal, if provided; otherwise use m_nVal
    }
};

C c(1);
c.foo();  // use 1
c.foo(2); // use 2

Это невозможно, поскольку стандарт C ++ гласит:

Нестатический элемент не должен использоватьсяв аргументе по умолчанию

Имеются следующие опции:

(1) Перегрузка foo():

class C
{
    int m_nVal;
public:
    C(int nVal) : m_nVal(nVal){}

    void foo()
    {
        // use m_nVal
    }

    void foo(int nVal)
    {
        // use nVal
    }
};

(2) Использовать статический член:

class C
{
    static int m_nVal;
public:         
    void foo(int nVal = m_nVal)
    {
        // use nVal, if provided; otherwise use m_nVal
    }
};

Я не хочу делать m_nVal статическим членом, поэтому вариант 1 кажется единственным.

Есть ли другие способы добиться этого?

Ответы [ 4 ]

6 голосов
/ 23 февраля 2012

Существуют и другие альтернативы, если вы хотите изменить интерфейс. Вы можете использовать boost::optional:

// untested:
void foo( boost::optional<int> val = boost::optional<int>() ) {
    int value;
    if ( val ) value = *val;
    else value = m_val;
    // Now use `value` in the function
}

Если вы не можете использовать boost, вы можете написать свою собственную обнуляемую оболочку. Вам просто нужно сохранить тип (int) и флаг, который определяет, установлен он или нет.

Следующая опция использует указатель, чтобы отметить, что аргумент является необязательным:

void foo( int *pval = 0 ) {
    int value = (pval? *pval : m_val);
    // use value from here on
}

Но опция с указателем запрещает использование rvalues ​​ в качестве аргументов функции (т. Е. Вам нужна правильная переменная для вызова функции, вы не можете сделать foo(1), а скорее нужно int x = 1; foo( &x );, что является болью).

Наконец, вы можете использовать свой подход, предлагая две перегрузки, одна из которых принимает аргумент, а другая - нет, и просто переходит к первой:

void foo( int val ) {
   // actual implementation
}
void foo() {
   foo( m_val );
}

Это может быть лучшим вариантом ...

2 голосов
/ 23 февраля 2012

Два варианта не эквивалентны.Создание элемента static не должно быть решением о том, хотите ли вы использовать его как метод по умолчанию или нет.

Если m_nVal логически связан с классом, а не с экземпляром, сделайте это static.

Если m_nVal относится к каждому объекту класса, не используйте его и используйте первый параметр.

0 голосов
/ 23 февраля 2012

Передача параметра по умолчанию будет означать, что компилятор должен передать его.Это означает, что для m_nVal компилятор будет использовать this->m_nVal.Это, в свою очередь, означало бы `foo (this-> m_nVal); '.

Это то, что я имею в виду:

c.foo(c.m_nVal);  // use 1 

Что позволило бы m_nVal private данные для доступа вне класса и нарушают основное правило C ++.

0 голосов
/ 23 февраля 2012
   class C
    {
        int m_nVal;
    public:

        C(int nVal) : m_nVal(nVal){}            

        void foo(int nVal = -1)
        {
        if(nVal == -1)
            nVal = m_nVal;

             // use nVal, if provided; otherwise use m_nVal
        }
    };

C c(1);
c.foo();  // use 1
c.foo(2); // use 2
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...