Yifan Lai
Yifan Lai

Reputation: 141

Dealing with cv-modifiers in the template argument

I am trying to implement some kind of wrapper template for memory management purposes:

template<typename T>
class Foo {

  T * var;
  bool cpy;
  Foo(T * inp, bool cpy): var(inp), cpy(cpy) {}

public:
  // named ctors
  static Foo<T> * newRef(T * inp){
    return new Foo(inp, false);
  }

  static Foo<T> * newCpy(const Foo<T> * foo){
    return new Foo(new T(*(foo->var)), true);
  }
  /* How to add cv variations to newCpy ? */

  ~Foo(){
    if (cpy) delete var;
  }
};

I am looking for a way to add in cv-variations in newCpy(), such as Foo<int>::newCpy(Foo<const int> *) and Foo<const int>::newCpy(Foo<int> *). My attempt looks like this:

template<typename T>
class Foo {
  using mT = typename std::remove_cv<T>::type;
  // T = const int -> mT = int

  /* ... */

  static Foo<T> * newCpy(const Foo<mT> * foo){
    return new Foo(new T(*(foo->var)), true);
  }
};

However this does not work for two reasons:

  1. If T is not const, then mT will be the same as T, and the two newCpy would have exactly the same signature as a result.

  2. Foo<T> does not have access to Foo<mT>::var

Is there any way around this?

Upvotes: 0

Views: 432

Answers (1)

brandonhewer
brandonhewer

Reputation: 46

An inversion of the const type qualifier can be achieved with the use of the meta-function conditional: https://en.cppreference.com/w/cpp/types/conditional

The following code requires C++17, however, to convert to C++14 simply replace occurrences of _v with ::value.

template <typename T>
using invert_const =
    std::conditional_t<std::is_const_v<T>, std::remove_const_t<T>, const T>;

For this particular question, the example use-case would then be

static Foo<T> * newCpy(const Foo<invert_const<T>> * foo) {
    return new Foo(new T(*(foo->var)), true);
}

In the example you have given, it is not clear that you intend to remove the volatile qualifier, however, if I have simply misunderstood the intended use-case, a similar inversion is possible with:

template <typename T>
using invert_volatile =
    std::conditional_t<std::is_volatile_v<T>, std::remove_volatile_t<T>, volatile T>;

These may also be composed

template <typename T>
using invert_cv = invert_volatile<invert_const<T>>;

The meta-function invert_cv may then be used in the following manner

static Foo<T> * newCpy(const Foo<invert_cv<T>> * foo) {
    return new Foo(new T(*(foo->var)), true);
}

Upvotes: 1

Related Questions