Overload [] subscript operator for std::any - c++

is there any way to overload the operator[] for std::any?
I have a struct looking like this:
struct Container {
public:
template <typename T>
void push_back(const T &t) {
m_container.push_back(t);
}
private:
std::vector<std::any> m_container;
}
Now I'd like to be able to access an element by index (which can be of any type).
I think of a visitor like
struct subscript_visitor {
std::string operator[](const size_t &idx) {
}
int operator[](const size_t &idx) {
}
...
}
But functions with the same return type reasonably cannot be declared.
Any idea how to solve this so that something like
Container c;
c.push_back(0);
std::cout << c[0];
Will work?

You need to store additional info, if you want to access the type later. You could do so by storing a function pointer to a specialization of a template function used for printing. You'll need to add one data member to the vector element per function you want to access though to make this work. std::variant may be preferrable in this scenario depending on the use case.
struct Container {
public:
template <typename T>
void push_back(T&& t) {
m_container.emplace_back(std::forward<T>(t));
}
struct Element
{
template<class U>
Element(U&& value)
: m_value(std::forward<U>(value)),
m_printFunction(&Container::Print<U>)
{
}
std::any m_value;
void (*m_printFunction)(std::ostream&, std::any const&);
};
Element const& operator[](size_t index) const
{
return m_container[index];
}
private:
template<class U>
static void Print(std::ostream& s, std::any const& value)
{
s << any_cast<U>(value);
}
std::vector<Element> m_container;
};
std::ostream& operator<<(std::ostream& s, Container::Element const& value)
{
value.m_printFunction(s, value.m_value);
return s;
}
int main()
{
Container c;
c.push_back(0);
c.push_back(std::string("Hello World"));
std::cout
<< c[0] << '\n'
<< c[1] << '\n';
}

Related

error: deduced class type 'tuple' in function return type

What I am doing
I am practicing c++ after 3 years. I needed to learn fast and broadly, so this example i am trying to solve might look odd to you.
I am using c++20, gcc 10.2.
I wanted to make a pythonic enumerate function that
Takes any container<T>
Yields std::tuple<int, T>
Where T is the type of items in the container
I wanted to try applying pythonic range as an argument of enumerate which
Takes (int start, int end, int step)
Yields int i from start to end every step
range (Not my code, I only added step functionality)
template <typename T>
class range_iterator;
template <typename T>
class range_impl
{
const T start_;
const T stop_;
const T step_;
public:
range_impl(T start, T stop, T step) : start_{start}, stop_{stop}, step_{step} {};
range_impl(T start, T stop) : start_{start}, stop_{stop}, step_{1} {};
range_impl(T stop) : start_{0}, stop_{stop}, step_{1} {};
range_iterator<T> begin() const
{
return range_iterator<T>{start_, step_};
}
range_iterator<T> end() const
{
return range_iterator<T>{stop_, step_};
}
};
template <typename T>
class range_iterator
{
T current_;
const T step_;
public:
range_iterator(T init, T step) : current_{init}, step_{step} {};
range_iterator<T> &operator++()
{
current_ += step_;
return *this;
}
bool operator!=(const range_iterator<T> &rhs) const
{
return current_ != rhs.current_;
}
T operator*() const
{
return current_;
}
};
template <typename T>
range_impl<T> range(const T start, const T stop, const T step)
{
return range_impl<T>(start, stop, step);
}
template <typename T>
range_impl<T> range(const T start, const T stop)
{
return range_impl<T>(start, stop);
}
template <typename T>
range_impl<T> range(const T stop)
{
return range_impl<T>(stop);
}
Can be used like following
#include <iostream>
int main()
{
for(auto i: range(0, 100 2)
{
std::cout << i << std::endl;
}
}
Problem code: enumerate
template <typename T>
class enumerate_iterator;
// Here, T should be a type of a container that contains type X
template <typename T>
class enumerate_impl
{
T impl;
public:
enumerate_impl<T>(T impl) : impl{impl} {/* empty */};
enumerate_iterator begin() const
{
return enumerate_iterator{impl.begin()};
}
enumerate_iterator end() const
{
return enumerate_iterator{impl.end()};
}
};
// Here, T should be a type of a iterator, I think. Confused myself.
template <typename T>
class enumerate_iterator
{
T iterator;
int i;
public:
enumerate_iterator(T iterator) : iterator{iterator}, i{0} {/* empty body */};
enumerate_iterator<T> &operator++()
{
i++;
iterator++;
return *this;
}
bool operator!=(const enumerate_iterator<T> &rhs) const
{
return iterator != rhs.iterator;
}
std::tuple operator*() const
{
return {i, *iterator};
}
};
template <typename T>
enumerate_impl<T> enumerate(T impl)
{
return enumerate_impl<T>{impl};
}
Expected usage
#include <iostream>
int main()
{
for (auto &[i, j] : enumerate(range(0, 100, 2)))
{
std::cout << i << " " << j << std::endl;
}
}
Gotten error (There actually tons of compilation error, but I want to try more on the others).
utility.cpp:186:20: error: deduced class type 'tuple' in function return type
186 | std::tuple operator*() const
I guessed this is complaining that you didn't tell me what type the tuple contains. But the thing is, I don't know what type T iterator contains. How would I tell return type is std::tuple<int, type T contains>?
Thanks for reading this long long question.
I think that perhaps, for enumerate_iterator, you might want its template type T to be a "base element type", not some compound "iteration type".
For example, if you were to choose to implement your iteration using raw memory pointers, then the enumerate_iterator's data member called iterator would have type T* (instead of its current T type).
And then, in that case, the definition of operator*() would be programmed as having a return type of std::tuple<int,T>

How to specialize function template for a container?

I have function template that implements storing POD into stream:
template<typename T>
void dumps(std::ostream &os, const T &t)
{
os.write(reinterpret_cast<const char *>(&t), sizeof(t));
}
Is there a way to specialize this template for containers to
store container size and then call general implementation for
container items?
This works for std::vector, std::set, and std::list. Haven't tested for any other container.
It also works for POD types. Tested with int and the following struct.
struct A
{
int a;
double b;
};
// Forward declaration of the wrapper function.
template<typename T>
void dumps(std::ostream &os, const T &t);
// Implementation for POD types
template<typename T>
void dumps(std::ostream &os, const T &t, std::true_type)
{
os.write(reinterpret_cast<const char *>(&t), sizeof(t));
}
// Implementation for container types
template<typename T>
void dumps(std::ostream &os, const T &t, std::false_type)
{
auto size = std::distance(t.begin(), t.end());
os.write(reinterpret_cast<const char *>(&size), sizeof(size));
for ( auto const& item : t)
{
dumps(os, item);
}
}
// Implementation of the wrapper function.
template<typename T>
void dumps(std::ostream &os, const T &t)
{
dumps(os, t, std::integral_constant<bool, std::is_pod<T>::value>());
}
You just need to specialise the template for each container type. For example, with a vector.
template<typename T>
void dumps(std::ostream &s, const typename std::vector<T> &t)
{
auto size = t.size();
s.write(<reinterpret_cast<const char *>(&size), sizeof(size);
for (auto const &item : t)
dumps(s, item); // using your dumps() for POD types
}
or (before C++11)
template<typename T>
void dumps(std::ostream &s, const typename std::vector<T> &t)
{
typename std::vector<T>::size_type size = t.size();
s.write(<reinterpret_cast<const char *>(&size), sizeof(size);
for (std::vector<T>::const_iterator item = t.begin(), end = t.end();
i != end; ++i)
dumps(s, *item); // using your dumps() for POD types
}
Similarly, specialise for other container types. Then it will also work for containers of containers.
Aside: this does assume you won't instantiate your templates for non-POD types. It is probably worth enforcing that (although I'll leave it as an exercise).

Can I explicitly instantiate template member of template class without instantiating the template class?

I want to explicitly instantiate template member but without instantiation of the template class. But I am getting compiler errors, so is this possible ? Here is my code:
//mytemplate.h
template <class T>
class mytemplate
{
public:
mytemplate(T* tt)
{
mT = tt;
}
template<class B>
void print(const B& bb);
T* mT;
};
//in mytemplate.cpp
#include "mytemplate.h"
template<typename T>
template<typename B>
void mytemplate<T>:: print(const B& bb)
{
B b = bb;
}
template<typename T> void mytemplate<T>::print<float>(const float&) const;
template<typename T> void mytemplate<T>::print<int>(const int&) const;
// main.cpp
int main()
{
int d =0;
mytemplate<int> k(&d);
k.print<float>(4.0);
}
With templates, it always helps to decompose the problem into the smallest possible building block. mytemplate::print can be written in terms of a call to a template free function.
This way you can achieve the effect of partial specialisation of a member function.
A leading question here is "what should the print() method do?". Here is an example in which mytemplate<T> provides a printing policy to a free function. There is no reason of course that the policy could not be some other class which has been constructed via some other (possibly specialised) template free function.
// Policy is a concept which supports 2 methods:
// print_prefix() and print_postfix()
//
template<class Policy, class B>
void print_with_policy(const Policy& policy, const B& value) const
{
policy.print_prefix();
cout << value;
policy.print_postifx();
}
template<class T>
struct mytemplate
{
// implement in terms of a free function
template<class B> void print(const B& value) {
print_with_policy(*this, value);
}
// policy concept implementation
void print_prefix() const {
cout << "prefix-";
}
void print_postfix() const {
cout << "-postfix";
}
};
extending the example to use a separate policy class with a specialisation for strings:
template<typename B>
struct default_policy {
default_policy(const B& value) : _value(value) {}
void operator()() const {
cout << "(" << _value << ")";
}
private:
const B& _value;
};
template<typename B>
struct quoted_policy {
quoted_policy(const B& value) : _value(value) {}
void operator()() const {
cout << '"' << _value << '"';
}
private:
const B& _value;
};
template<class B>
default_policy<B> make_policy(const B& value) {
return default_policy<B>(value);
}
// overload for B being a string
quoted_policy<std::string> make_policy(const std::string& value) {
return quoted_policy<std::string>(value);
}
template<class T>
struct mytemplate
{
// implement in terms of a free function
template<class B> void print(const B& value) {
make_policy(value)();
cout << endl;
}
};
int main()
{
struct foo{};
mytemplate<foo> fooplate;
fooplate.print(int(8));
fooplate.print(std::string { "a string" });
fooplate.print("not a string");
return 0;
}
output:
(8)
"a string"
(not a string)

implementing a generic binary function with a class and functor as template parameters

I am trying to wrap some templated functions into some binary functors like below. When I try to compile the code I have the error
error: no match for call to ‘(QtyAsc) (myobj&, myobj&)
I thought that being operator() in QtyAsc a function in a class, the template deduction mechanism would have worked but it seems that the compiler doesn't accept myobj classes as valid types for it.
Is it maybe because of the call to boost::bind? I was trying to provide a default implementation for the second templated argument (unfortunately I cannot use C++11 with default templated arguments).
class myobj {
public:
myobj(int val) : qty_(val) {}
int qty() { return qty_;}
private:
int qty_;
};
template<class T>
int get_quantity(const T& o) {
throw runtime_error("get_quantity<T> not implemented");
}
template<>
int get_quantity(const myobj& o) {
return o.qty();
}
struct QtyAsc {
template<class T, class QEx >
bool operator()(const T& o1, const T& o2, QEx extr = boost::bind(&get_quantity<T>,_1)) const {
if(extr(o1) < extr(o2))
return true;
return false;
}
};
int main() {
myobj t1(10),t2(20);
QtyAsc asc;
if(asc(t1,t2))
cout << "Yes" << endl;
}
If you can't use C++11, just provide an additional overload:
struct QtyAsc {
template<class T, class QEx >
bool operator()(const T& o1, const T& o2, QEx extr) const {
return extr(o1) < extr(o2);
}
template<class T>
bool operator()(const T& o1, const T& o2) const {
return operator()(o1, o2, &get_quantity<T>);
}
};
(I've omitted the unnecessary boost::bind.) Also, you will need to declare myobj::qty to be const:
int qty() const {
return qty_;
}
since you want to invoke it on const objects. (Live demo)

Operator templates in C++

If I want to create a function template, where the template parameter isn't used in the argument list, I can do it thusly:
template<T>
T myFunction()
{
//return some T
}
But the invocation must specify the 'T' to use, as the compiler doesn't know how to work it out.
myFunction<int>();
But, suppose I wanted to do something similar, but for the '[]' operator.
template
T SomeObject::operator [ unsigned int ]
{
//Return some T
}
Is there any way to invoke this operator?
This doesn't appear valid:
SomeObject a;
a<int>[3];
This should work:
class C
{
public:
template <class T>
T operator[](int n)
{
return T();
}
};
void foo()
{
C c;
int x = c.operator[]<int>(0);
}
But it's of no real value because you'd always have to specify the type, and so it looks like a very ugly function call - the point of an operator overload is to look like an operator invocation.
Boost.Program_options uses this neat syntax:
int& i = a["option"].as<int>();
Which is achieved with something like this:
class variable_value
{
public:
variable_value(const boost::any& value) : m_value(value) {}
template<class T>
const T& as() const {
return boost::any_cast<const T&>(m_value);
}
template<class T>
T& as() {
return boost::any_cast<T&>(m_value);
}
private:
boost::any m_value;
};
class variables_map
{
public:
const variable_value& operator[](const std::string& name) const
{
return m_variables[name];
}
variable_value& operator[](const std::string& name)
{
return m_variables[name];
}
private:
std::map<std::string, variable_value> m_variables;
};
You could adapt this idea to suit your own needs.
Like with any operator, the function name is operator#, so:
a.operator[]<int>(3);
You can use a.operator[]<int>(1);
But why do you want this?
This may not be an optimal solution, but you could directly call the operator as such:
a.operator[](3);
I tried this in g++ with the following test:
class MyClass {
public:
template<class T>
T operator[](unsigned int) {
// do something
return T();
}
};
int main(int argc, char* argv[]) {
MyClass test;
test.operator[]<int>(0);
//test<int>[0]; // doesn't compile, as you mentioned
return 0;
}
If you need to define operator[] then probably define the template at the class level. Something like this:
template<class T>
class C
{
public:
T operator[](int n)
{
return T();
}
};
int main()
{
C<int> c;
int x = c[0];
return 0;
}
I have a hard time coming up with an example where this would be needed (couldn't you just overload the operator instead?), but here's my thoughts anyway:
Since you cannot use the infix operator syntax with templatized operators, you might want to do the template instantiation before you call the operator. A proxy might be a way to do this.
class some_class {
private:
template<class T> class proxy {
some_class* that_;
public:
proxy(some_class* that) : that_(that) {}
T& operator[](std::size_type idx) {return that->get<T>(idx);}
};
template<class T> class const_proxy {
some_class* that_;
public:
proxy(const some_class* that) : that_(that) {}
const T& operator[](std::size_type idx) const {return that->get<T>(idx);}
};
template< typename T > proxy<T> get_array() {return proxy<T>(this);}
template< typename T > const_proxy<T> get_array() const {return proxy<T>(this);}
template< typename T > T& get(std::size_t idx) {/* whatever */}
template< typename T > const T& get(std::size_t idx) const {/* whatever */}
};
// This is a lousy use case.
// Did I already say I have a hard time imagining how to use this?
template< typename T >
void f(some_class& some_object, sid::size_t idx)
{
T& = some_object.get_array<T>()[idx];
}