Как объявить функции-члены как постоянные или нет в зависимости от того, является ли параметр шаблона постоянным или нет - PullRequest
0 голосов
/ 19 июня 2019
template <typename T>
struct A {
  A(T a) : _value{a} {}
  T& value() {return _value;}
// if (std::is_const<Tp>) T& value() const {return _value;}
private:
  T _value;
};
int main() {
  A<int> mutA{1};
  cout << "mutA: " << mutA.value() << endl;
  mutA.value() += 10;
  cout << "mutA: " << mutA.value() << endl;
  A<const int> immA{2};
  cout << "immA: " << immA.value() << endl;
  // error immA.value() += 10;
}

A предназначен для создания экземпляров: -

A<int> mutableA{1};

или

A<const int> immutableA{1};

Чего я хотел бы добиться, так это того, что если параметр шаблона Tp равен const (т.е. std::is_const<Tp>::value имеет значение true), то функция-член T& value() будет объявлена ​​как T& value() const;

Код ниже не работает, но что-то эквивалентное было бы хорошо: -

if constexpr (std::is_const<Tp>::value) {
  T& value() {return _value;}
}
else {
  T& value() const {return _value;}
}

A имеет много функций, поэтому определение его дважды не будет решением.

Ответы [ 2 ]

1 голос
/ 19 июня 2019

Просто объявите оба, но убедитесь, что версия const разрешает только const доступ:

template <typename T>
struct A {
  A(T a) : _value{a} {}
  T& value() {return _value;}
  const T& value() const {return _value;}
private:
  T _value;
};

Рассмотрим варианты использования:

void show(int);
void modify(int&);

void f1(A<int>& a) {
    show(a.value());
    modify(a.value());
}

Хорошо, a.value() возвращает int& здесь, поэтому переменная может быть изменена.

void f2(A<const int>& a) {
    show(a.value());
    // modify(a.value()); // invalid
}

Здесь, даже если мы вызываем T& value();, поскольку T равен const int, тип возвращаемого значения const int&, и значение не может быть изменено.

void f3(const A<int>& a) {
    show(a.value());
    // modify(a.value()); // invalid
}

Теперь мы вызываем const T& value() const ;, поэтому тип возвращаемого значения const int&. Снова значение не может быть изменено.

void f4(const A<const int>& a) {
    show(a.value());
    // modify(a.value()); // invalid
}

Этот также называется const T& value() const. При T=const int язык «сворачивает» избыточный const, так что const T совпадает с const int, а тип возвращаемого значения - const int&. Таким образом, значение не может быть изменено.

0 голосов
/ 19 июня 2019

В конце концов выяснили, как это сделать, используя std :: enable_if.

template <typename T>
struct A {
  A(T a) : _value{a} {}
  template <typename Tp = T>
  std::enable_if_t<std::is_const<Tp>::value, T&> value() const {return _value;}
  template <typename Tp = T>
  std::enable_if_t<!std::is_const<Tp>::value, T&> value() {return _value;}
private:
  T _value;
};

Это работает из-за «Ошибка замены не является ошибкой ( SFINAE )». Обратите внимание, что вы не можете использовать параметр шаблона T напрямую, так как для работы SFINAE должна произойти подстановка. Предоставление параметра по умолчанию, как в template <typename Tp = T>, делает свое дело.

Если условие std::enable_if_t ложно, функция не будет объявлена. Если это правда, тогда второй параметр, T& в этом случае, является результатом std::enable_if_t.

std::enable_if_t доступен только с C ++ 14 и выше. Если вы используете C ++ 11, вам придется использовать более подробную форму typename std::enable_if<std::is_const<Tp>::value, T&>::type.

template <typename T>
struct A {
  A(T a) : _value{a} {}
  template <typename Tp = T>
  typename std::enable_if<std::is_const<Tp>::value, T&>::type value() const {return _value;}
  template <typename Tp = T>
  typename std::enable_if<!std::is_const<Tp>::value, T&>::type value() {return _value;}
private:
  T _value;
};
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...