Tom de Geus
Tom de Geus

Reputation: 5965

Remove const from nested template

I have a templated class which has its own storage, but can also be used to 'view' (or even modify) a bigger array using a pointer to some position in the array. Viewing the bigger array is done using e.g. (see full example below):

Tensor<double> t;
t.view(&array[i]);

When the array is marked const the following can be used

Tensor<const double> t;
t.view(&array[i]);

My problem is now:

I want to write a function with ONE template argument for Tensor<...>, that can be used to map the const-array and to modify a copy of the map. How can I remove the const from a 'nested template'? Or, if that is not possible, how can I use the map without marking it const in the template?

Note that I have currently no conversion from Tensor<const double> to Tensor<double>.


A simple, complete, example showing this behavior is

#include <iostream>
#include <vector>

template<class T>
class Tensor
{
private:
  T m_container[4];
  T *m_data;

public:
  // constructor
  Tensor() { m_data = &m_container[0];};

  // copy constructor
  Tensor(const Tensor& other)
  {
    for ( auto i = 0 ; i < 4 ; ++i )
      m_container[i] = other[i];

    m_data = &m_container[0];
  }

  // index operator
  T& operator[](size_t i) { return m_data[i]; }
  const T& operator[](size_t i) const { return m_data[i]; }

  // point to external object
  void view(T *data) { m_data = data; }
};


template<class T>
T someOperation(std::vector<double> &input, size_t i)
{
  T t;

  t.view(&input[i*4]);

  // ... some code that uses "t" but does not modify it

  T s = t;

  return s;
}


int main()
{
  std::vector<double> matrix = { 1., 2., 3., 4., 11., 12., 13., 14. };

  Tensor<double> tensor = someOperation<Tensor<double>>(matrix, 1);

  return 0;
}

Compiled for example using clang++ -std=c++14 so.cpp.

Now I want to change the signature of the function to

template<class T>
T someOperation(const std::vector<double> &input, size_t i)

The above function can be used using

someOperation<Tensor<const double>>(...)

But obviously I cannot change s anymore. How can I solve this?

Upvotes: 1

Views: 409

Answers (1)

Aconcagua
Aconcagua

Reputation: 25516

Consider std::remove_const:

template<typename T>
void f(T& t);

double const d = 1.0;
f(d);

template<typename T>
void f(T& t)
{
    T ct = t;
    //ct += 1.0; // refuses to compile!
    typename std::remove_const<T>::type nct = t;
    nct += 1.0;  // fine...
}

Edit: OK, only half of the truth...

With your example provided, matter gets a little more complicated, as you need to exchange the inner template type...

This can be done with a template template function:

template<template < class > class T, typename V>
auto someOperation(std::vector<double>& input, size_t i)
{
    T<V> t;
    t.view(&input[i*4]);
    T<typename std::remove_const<V>::type> s = t;
    return s;
}

However, this imposes quite some trouble on you:

  1. Constant members cannot be initialized in the constructor body, so you need:

    Tensor(Tensor const& other)
        : m_container { other[0], other[1], other[2], other[3] },
          m_data(m_container)
    { }

  2. Tensor<double> and Tensor<double const> are entirely different types, so they need to be constructible one from another:

    Tensor(Tensor<typename std::remove_const<T>::type> const& other);
    Tensor(Tensor <T const> const& other);
    // both with same implementation as above
    We don't need all combinations, but we get them for free... Alternatively, a template constructor:
    template<typename TT>
    Tensor(Tensor<TT> const& other);
    This would even allow you to initialize e. g. a double tensor from e. g. an int tensor – if desired or not, decide you...

Upvotes: 2

Related Questions