Reputation: 5965
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
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:
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) { }
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 aboveWe 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