Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Add const to type if template arg is const

I have a class:

struct Foo {
  vector<float> data;
};

and I have a templated function that takes a Foo&:

template<typename T>
void f(T& arg) {
  using ftype = float *;    // <-- would like this to be const float * if T is const
  ftype ptr = &arg.data[0];
  // ... do stuff with ptr ...
}

How can I make ptr be const float * iff T is const? I know about add_const and is_const but don't see how to use them here. (My real struct is more complicated and I don't have direct access to its internals; it's actually an OpenCV cv::Mat.) I can use recent (C++14/C++17) features if needed.

I'll use it like this:

Foo foo1 = Foo();
f(foo1); // modifiable in f
const Foo cfoo = Foo();
f(cfoo); // const, should not be modifiable in f
like image 763
GaryO Avatar asked Sep 28 '18 16:09

GaryO


2 Answers

Most likely, you actually just want the type of the expression &arg.data[0], for which you can use decltype.

You can also use std::conditional to distinguish the cases.

template<typename T>
void f(T& arg) {
  // C++17: using ftype = std::conditional_t<std::is_const_v<T>, const float *, float *>;
  using ftype = typename std::conditional<std::is_const<T>::value, const float *, float *>::type;

  ftype ptr = &arg.data[0];
  // ... do stuff with ptr ...
}

If instead of float *, you had a second type parameter U, you would include std::add_const

template<typename T, typename U = float *>
void f(T& arg) {
  // C++17: using ftype = std::conditional_t<std::is_const_v<T>, std::add_const_t<U>, U>;
  using ftype = typename std::conditional<std::is_const<T>::value, typename std::add_const<U>::type, U>::type;
  // ... do stuff with ftype ...
}

I have marked where C++14 and C++17 has nicer syntax for equivalent use. C++11 lack of template usings and template variables results in verbose type functions :(.

like image 125
Caleth Avatar answered Oct 26 '22 04:10

Caleth


template<class Src, class Dst>
using transcribe_const_t = std::conditional_t<std::is_const<Src>{}, Dst const, Dst>;
template<class Src, class Dst>
using transcribe_volatile_t = std::conditional_t<std::is_volatile<Src>{}, Dst volatile, Dst>;
template<class Src, class Dst>
using transcribe_cv_t = transcribe_const_t< Src, transcribe_volatile_t< Src, Dst> >;

now

template<typename T>
void f(T& arg) {
  using ftype = transcribe_cv_t<T, float>*;
  ftype ptr = &arg.data[0];
  // ... do stuff with ptr ...
}

does what you ask (and a bit more).

like image 25
Yakk - Adam Nevraumont Avatar answered Oct 26 '22 04:10

Yakk - Adam Nevraumont