Allowing both pre-computed and computed-on-the-fly results - c++

Consider:
template <typename T>
struct C {
std::vector<int> f(const T &t) const {
return t.f();
}
};
T::f must compute the required vector. However, some T's pre-compute the vector and we would like to avoid creating a copy in such a case. Here is my attempt:
struct A {
std::vector<int> f() const {
std::vector<int> res{10, 20, 30}; // computing the vector.
return res;
}
};
struct B {
const std::vector<int> &f() const {
return v_; // returning reference to pre-computed vector.
}
private:
std::vector<int> v_{1, 2, 3};
};
template <typename T>
struct C {
const std::vector<int> &f(const T &t) const {
return t.f();
}
};
int main() {
using T = B; // For A, we get an error about returning reference to a local.
C<T> c;
T t;
c.f(t);
return 0;
}
As the comment in main indicates, for T=A, the above code is in error as it is returning a reference to the local variable. How can I accommodate for both T=A and T=B, such that the pre-computed vector B::v_ does not get copied?

Make C::f return the exact same type as T::f, by using decltype:
template <typename T>
struct C {
auto f(const T &t) const -> decltype(t.f()) {
return t.f();
}
};
This will return by value when T = A, and by const& when T = B.
wandbox example

Your attempt isn't testing what it should. For the pre-computed results to be useful, they need to be persistent. One class needs to do both the computation and the storage.
For example,
struct A {
std::vector<int> const & f() const {
if ( v_.empty() ) {
v_ = {10, 20, 30}; // computing the vector.
}
return v_;
}
private:
mutable std::vector<int> v_;
};
Another architecture would be to store all the results in one std::map< X, std::vector > (or unordered_map), if there's some type X defining the domain of the function.

Related

Store either constant or non constant reference within the same class template

The example below is degenerate because I would like to learn about the concept.
Let's say we would like to have a 1-element view of an array.
My question is how to make it work with both const and non-const objects.
I know why the second block in the code below does not compile but I don't know how to organize the code to serve both cases.
#include <cassert>
#include <array>
template <typename T>
class View {
private:
const std::size_t index_;
T &t_;
using value_type = typename T::value_type;
public:
View(T &t, std::size_t index) : t_{t}, index_{index} {}
const value_type &value() const { return t_[index_]; }
value_type &value() { return t_[index_]; }
};
int main() {
using Array = std::array<int, 2>;
// The block below works
{
Array array{0, 0};
View<Array> view(array, 0);
view.value() = 5;
assert(array[0] == 5);
}
// The block below gives a compilation error
{
const Array array{5, 5};
View<Array> view(array, 0);
assert(view.value() == 5);
}
}
The following works:
#include <cassert>
#include <array>
template <typename T>
class View {
private:
using value_type = typename T::value_type;
T &t_;
const std::size_t index_;
public:
View(T &t, std::size_t index) : t_{t}, index_{index} {}
const value_type &value() const { return t_[index_]; }
template<class Arr = T, class = typename std::enable_if<!std::is_const<Arr>::value>::type>
value_type &value() { return t_[index_]; }
};
int main() {
using Array = std::array<int, 2>;
// The block below works
{
Array array{0, 0};
View<Array> view(array, 0);
view.value() = 5;
assert(array[0] == 5);
}
// The block below gives a compilation error
{
const Array array{5, 5};
View<const Array> view(array, 0);
assert(view.value() == 5);
}
}
If you give the View a const Array you also have to specify a const Array as template argument.
But then returning a non-const reference with value() doesn't work anymore, so we disable this function with SFINAE, if the array type is const.
PS: You wouldn't have the last problem if your class named View were indeed what one would expect under a view, i.e. non-modifiying and not even having a method returning a non-const reference.

Intrusive reflection like functionality for c++?

I want to create a function template that creates a list of all legal/valid instances of some class. The class itself is somehow informed about the values that each of its members can take. Function template:
template <typename T>
std::list<T> PossibleInstantiations();
Now, if SomeClass somehow contains information about legal instantiations of all its members (in below example, legal instantiations of i are 1,4,5 and legal instantiations of j are 1.0, 4.5), then
PossibleInstantiations<SomeClass>();
should yield a list containing elements {SomeClass(1,1.0), SomeClass(1,4.5), SomeClass(4,1.0), SomeClass(4,4.5), SomeClass(5,1.0), SomeClass(5,4.5)}.
Of course, adding extra elements (+ associated valid values) should automatically be handled by PossibleInstantiations.
Someclass would be implemented something like below. In what way should the plumbing be added to client classes (e.g. MyClass), and how should PossibleInstantiations be implemented?
class SomeClass
{
public:
int i;
static std::list<int> ValidValuesFori();
double j;
static std::list<double> ValidValuesForj();
SomeClass(int i, double j);
//int k;
//static std::list<int> ValidValuesFork(); //could be implemented at some later stage.
//Which would mean the constructor becomes:
//SomeClass(int i, int j, int k)
//...
//Extra wiring for pointing out that i and ValidValuesFori belong to each other,
//and perhaps for pointing out that i is the first element in the constructor, or so?
//..
};
static std::list<int> SomeClass::ValidValuesFori()
{
return std::list<int>{1, 4, 5};
//Other options:
//std::list<int> ValidValues;
//for (int i = 0; i < 1000; i++)
//{
// if (i % 3 == 0)
// ValidValues.push_back(i);
//}
//return ValidValues;
}
static std::list<double> SomeClass::ValidValuesForj()
{
return std::list<double>{1.0, 4.5};
}
SomeClass::SomeClass(int i, double j)//or other constructor
:i{ i }, j{ j } {}
Why make it hard if you can make it easy? You already say that SomeClass should know which values are allowed for its members. You could make this explicit by moving GetPossibleImplementations() to the class:
class SomeClass
{
public:
static std::vector<SomeClass> GetPossibleImplementations()
{
std::vector<SomeClass> values;
for (int i : ValidValuesFori())
for (double j : ValidValuesForj())
values.push_back(SomeClass(i, j));
return values;
}
// other methods
// [...]
}
Then you can still add the template function, if you need it:
template <typename T>
std::vector<T> GetPossibleImplementations()
{
return T::GetPossibleImplementations();
}
Moving the logic into the class has the following advantages:
Only the class knows which constructor args are valid, so it makes sense to have the logic there.
The cartesian product of valid argument values may not be sufficient for all cases. What if some value of i conflicts with some value of j?
You can still move some logic into helper functions, for example, the cartesian product.
There are situations where you cannot change the implementation of SomeClass and you need an external solution. Even in that case, I think you should keep the logic class-specific: Declare the generic function GetPossibleImplementations<T>() as above, but implement it only for the specific classes:
template <typename T>
std::vector<T> GetPossibleImplementations();
template <>
std::vector<SomeClass> GetPossibleImplementations<SomeClass>()
{
std::vector<SomeClass> values;
for (int i : SomeClass::ValidValuesFori())
for (double j : SomeClass::ValidValuesForj())
values.push_back(SomeClass(i, j));
return values;
}
The main differences between the two versions is that the first version yields a compile error if the template argument T does not support T::GetPossibleImplementations() and the second version yields a link error if GetPossibleImplementations<T> is not implemented.
With Cartesian product, we might do:
// cartesian_product_imp(f, v...) means
// "do `f` for each element of cartesian product of v..."
template<typename F>
void cartesian_product_imp(F f) {
f();
}
template<typename F, typename H, typename... Ts>
void cartesian_product_imp(F f, std::vector<H> const& h,
std::vector<Ts> const&... vs) {
for (H const& he: h) {
cartesian_product_imp([&](Ts const&... ts){
f(he, ts...);
}, vs...);
}
}
template <typename... Ts>
std::vector<std::tuple<Ts...>> cartesian_product(std::vector<Ts> const&... vs) {
std::vector<std::tuple<Ts...>> res;
cartesian_product_imp([&](Ts const&... ts){
res.emplace_back(ts...);
}, vs...);
return res;
}
template <typename T>
std::vector<T> PossibleInstantiations()
{
auto validValuesByArgs = T::ValidValuesForArgs();
auto validArgs =
std::apply([](const auto&... args){ return cartesian_product(args...); },
validValuesByArgs);
std::vector<T> res;
std::transform(validArgs.begin(), validArgs.end(),
std::back_inserter(res),
[](const auto& t){
return std::apply([](const auto&... args) { return T(args...); },
t);
});
return res;
}
With
class SomeClass
{
public:
int i;
double j;
const std::string s;
static std::tuple<std::vector<int>, std::vector<double>, std::vector<std::string>>
ValidValuesForArgs() { return {{1, 4, 5}, {1.1, 4.5}, {"foo", "bar"}}; }
SomeClass(int i, double j, const std::string& s) : i(i), j(j), s(s) {}
};
Demo

How to write template function for general std::vector push_back?

I have two or different types of std::vector.
struct data{
int a;
int b;
int c;
};
std::vector<int> val1;
std::vector<data> val2;
Now I want to write a template function that would work for both val1 and val2.
template<typename t>
void my_function(t s){
s.push_back(...); // based on s i.e it could be std::vector<int> or std::vector<data>
}
my_function<std::vector<int>>(val1);
my_function<std::vector<data>>(val2);
The problem I am facing is how can I say in the code that if the type is std::vector<int> do push back of s.push_back({1}) vs if std::vector<data> do s.push_back({1,2,3});
Forget templates. Simple overloading should solve your problem:
void my_function(const data& d) {
val2.push_back(d);
}
void my_function(int n) {
val1.push_back(n);
}
Seems that you want to specialize your template function,
you can do for example:
struct data{
int a;
int b;
int c;
};
std::vector<int> val1;
std::vector<data> val2;
template<typename t> void my_function(t s);
template<>
void my_function(std::vector<int> s){
s.push_back({1});
}
template<>
void my_function(std::vector<data> s){
s.push_back({1,2,3});
}
int main()
{
my_function(val1);
my_function(val2);
}
Not sure it's what you looking for...
You can templatize my_function() espliciting std::vector and extracting the type contained in this way
template <typename T>
void my_function(std::vector<T> & s)
{ s.push_back(getTval<T>()); }
(off topic: observe that I've added a & for parameter s; otherwise you pass the vector s as a copy and the push_back() add a value only in the copy that is destroyed exiting from the function)
But this solution doesn't avoid the need of a function specialization; it simply move this need in implementation of getVal().
template <typename T>
T getTval ();
template <>
int getTval<int> ()
{ return 1; }
template <>
data getTval<data> ()
{ return {1, 2, 3}; }
This can be usefull if my_function() is a great and complex solution where the push_back() is the only point where the data contained in the vector change the code. Otherwise, I suppose that can be better overload or specialize the same my_function().

C++ template class taking both const and non-const types

I would like to have a wrapper class that keeps and returns a pointer to some element of a wrapped container. It looks like:
template <typename T>
class VectorWrapper
{
public:
VectorWrapper(vector<T>& container) {
m_pointer = &container[0];
}
T* GetPointer() { return m_pointer; }
private:
T* m_pointer;
};
The problem is the input container can be a const type sometimes. In this case, is there an elegant way to avoid another implementation of VectorWrapper that rather returns const T*?
My approach (without luck) was the following:
template <typename T>
VectorWrapper<T> make_vector_wrapper(vector<T>& container) {
return VectorWrapper<T>(container);
}
template <typename T>
VectorWrapper<T> make_vector_wrapper(const vector<T>& container) {
// I'm stuck here. return VectorWrapper<const T>(container); doesn't work.
}
void Foo(const vector<int>& const_container) {
vector<int> mutable_container(10);
auto v1 = make_vector_wrapper(mutable_container);
*(v1.GetPointer()) = 1; // Ok
auto v2 = make_vector_wrapper(const_container);
int x = *(v2.GetPointer()); // Ok
*(v2.GetPointer()) = 1; // Would like compile error
}
You could template on the container and not the element, since it is the container that is const. Here is a quick mock-up (which does not work if the vector is relocated):
#include <iostream>
#include <vector>
template <typename T>
class VectorWrapper
{
using value_type = std::remove_reference_t<decltype(((T*)nullptr)->at(0))>;
public:
VectorWrapper(T& container) {
m_pointer = &container[0];
}
value_type* GetPointer() { return m_pointer; }
private:
value_type* m_pointer;
};
template <typename T>
VectorWrapper<T> make_vector_wrapper(T& container) {
return VectorWrapper<T>(container);
}
int main() {
std::vector<int> mutable_vector(10);
auto v1 = make_vector_wrapper(mutable_vector);
*(v1.GetPointer()) = 1; // Ok
const std::vector<int> const_vector(10);
auto v2 = make_vector_wrapper(const_vector);
// *(v2.GetPointer()) = 1; // error
}
Edit:
Here is a simpler solution (C++14 for auto return type), that also handles relocation of the underlying vectors data.
template <typename T>
class VectorWrapper
{
T& m_container;
public:
VectorWrapper(T& container) : m_container(container) {}
auto GetPointer() { return m_container.data(); }
};
Update:
It will also work for other container classes such as std::string and std::array
std::string mutable_string;
auto s1 = make_vector_wrapper(mutable_string);
// *(s1.GetPointer()) = 1; // error, sd::string::data returns char const *
std::array<int, 4> mutable_array;
auto a1 = make_vector_wrapper(mutable_array);
*(a1.GetPointer()) = 1; // Ok
const std::array<int, 4> const_array = {1,2,3,4};
auto a2 = make_vector_wrapper(const_array);
// *(a2.GetPointer()) = 1; // error

Passing a default value list to a template class

Not sure if this can be done using templates but I want to give it a try.
I have a template class which takes any struct, stores it and returns it. Additionally, I want an interface that resets the struct's data whenever requested.
#define MYDEFAULT {1,2,3}
template < typename ITEM, ITEM Default>
class myClass{
public:
myClass(ITEM item) : _item(item) {}
const ITEM* get(){
return &_item;
}
void reset(){
_item = Default;
}
ITEM _item;
};
// Set to default when instantiated
myClass<myStruct, MYDEFAULT> ABC(MYDEFAULT);
Of course that's not working at all, but what I want to achieve is the replacement of Default in reset(). I mean it would work if _item would be of type int.
How can this be realized?
EDIT: I want something like this:
template <typename Y, Y T>
class myclass {
public:
void reset() {
xxx = T;
}
Y xxx{10};
};
void test()
{
myclass<int, 5> _myclass;
}
Initially xxx is 10 and after invoking reset it is 5. This works, so it seems it is not possible for POD or class types?
EDIT2: It seems it is all about non-type template-arguments. https://stackoverflow.com/a/2183121/221226
So there is no way around traits when using structs.
As a viable solution, you can use a trait class as shown in the following working example:
#include<cassert>
struct S {
int i;
};
template<typename T>
struct Traits {
static constexpr auto def() { return T{}; }
};
template<>
struct Traits<S> {
static constexpr auto def() { return S{42}; }
};
template <typename ITEM>
class myClass {
public:
myClass(): _item(Traits<ITEM>::def()) {}
myClass(ITEM item): _item(item) {}
const ITEM* get() {
return &_item;
}
void reset() {
_item = Traits<ITEM>::def();
}
ITEM _item;
};
int main() {
myClass<S> ABC{};
myClass<int> is;
assert((ABC.get()->i == 42));
assert((*is.get() == 0));
}
The basic trait uses the default constructor of the type ITEM.
You can then specialize it whenever you want a different defaulted value for a specific class.
The same can be accomplished even with a factory function as:
template<typename T>
constexpr auto def() { return T{}; }
template<>
constexpr auto def<S>() { return S{42}; }
Anyway, traits can easily provide more types and functions all at once.
You can maybe simulate it using a data structure with a data member of type std::array.
A minimal, working example follows:
#include<cstddef>
#include<array>
#include<cassert>
template<typename T, T... I>
struct S {
S(): arr{ I... } {}
S(const T (&val)[sizeof...(I)]) {
for(std::size_t i = 0; i < sizeof...(I); ++i) {
arr[i] = val[i];
}
}
const T * get() {
return arr.data();
}
void reset() {
arr = { I... };
}
private:
std::array<T, sizeof...(I)> arr;
};
int main() {
S<int, 1, 3, 5> s{{ 0, 1, 2 }};
assert(s.get()[1] == 1);
s.reset();
assert(s.get()[1] == 3);
}
I'm not sure I got exactly what you are asking for, but the interface in the example is close to the one in the question and the implementation details should not affect the users of your class.