如何将成员函数声明为const取决于模板参数是否为const

时间:2019-06-19 12:25:43

标签: c++17

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

我要实现的是,如果模板参数Tpconst(即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 个答案:

答案 0 :(得分:1)

只需声明两者,但确保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();,由于Tconst 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 Tconst int相同,返回类型为const int&。因此该值无法修改。

答案 1 :(得分:0)

最终弄清楚了如何使用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的条件为false,则不会声明该函数。如果为true,则第二个参数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;
};