is it possible to construct variadic arguments for function by overloading operator comma of the argument? i want to see an example how to do so.., maybe something like this:
template <typename T> class ArgList {
public:
ArgList(const T& a);
ArgList<T>& operator,(const T& a,const T& b);
}
//declaration
void myFunction(ArgList<int> list);
//in use:
myFunction(1,2,3,4);
//or maybe:
myFunction(ArgList<int>(1),2,3,4);
It is sort-of possible, but the usage won't look very nice. For exxample:
#include <vector>
#include <iostream>
#include <algorithm>
#include <iterator>
template <class T>
class list_of
{
std::vector<T> data;
public:
typedef typename std::vector<T>::const_iterator const_iterator;
const_iterator begin() const { return data.begin(); }
const_iterator end() const { return data.end(); }
list_of& operator, (const T& t) {
data.push_back(t);
return *this;
}
};
void print(const list_of<int>& args)
{
std::copy(args.begin(), args.end(), std::ostream_iterator<int>(std::cout, " "));
}
int main()
{
print( (list_of<int>(), 1, 2, 3, 4, 5) );
}
This shortcoming will be fixed in C++0x where you can do:
void print(const std::initializer_list<int>& args)
{
std::copy(args.begin(), args.end(), std::ostream_iterator<int>(std::cout, " "));
}
int main()
{
print( {1, 2, 3, 4, 5} );
}
or even with mixed types:
template <class T>
void print(const T& t)
{
std::cout << t;
}
template <class Arg1, class ...ArgN>
void print(const Arg1& a1, const ArgN& ...an)
{
std::cout << a1 << ' ';
print(an...);
}
int main()
{
print( 1, 2.4, 'u', "hello world" );
}
Operators have a fixed number of parameters. You cannot change that. The comma operator takes two arguments. So no. You can roll a custom, cascading version though, with some effort.
Maybe something like this:
class MyArgList {
public:
typedef std::list<boost::any> ManyList;
template <typename T>
MyArgList& operator, (const T& val) {
elems.push_back(val);
return *this;
}
ManyList::iterator begin() {return elems.begin();}
...
private:
ManyList elems;
};
Usage would be:
void foo(MyArgList& list);
foo((myArgList(),1,2,3,4,5));
No, it isn't. The list of values separated by the comma operator will be evaluated as a single value. For example:
1,2,3
will result in a single value, 3.
Related
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';
}
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>
I would like to hide a vector field in my class but allow easy iteration through its elements but nothing else. So that class's client would be able to do
for (auto element : foo.getElements()) { }
but not
foo.getElements()[42];
Is there some simple way of achieving this w/o creating new confusing types?
I cannot say what is and is not a "new confusing type". But this is sufficient for the needs of a range-based for:
template<typename Iter>
class iterator_range
{
public:
iterator_range(Iter beg, Iter end) : beg_(beg), end_(end) {}
Iter begin() const {return beg_;}
Iter end() const {return end_;}
private:
Iter beg_, end_;
};
The Range TS adds more complexity to what constitutes a "range", but this is good enough for range-based for. So your foo.getElements function would look like this:
auto getElements()
{
return iterator_range<vector<T>::iterator>(vec.begin(), vec.end());
}
auto getElements() const
{
return iterator_range<vector<T>::const_iterator>(vec.begin(), vec.end());
};
You can use an higher-order function to only expose iteration functionality:
class something
{
private:
std::vector<item> _items;
public:
template <typename F>
void for_items(F&& f)
{
for(auto& i : _items) f(i);
}
};
Usage:
something x;
x.for_items([](auto& item){ /* ... */ });
The advantages of this pattern are:
Simple to implement (no need for any "proxy" class);
Can transparently change std::vector to something else without breaking the user.
To be completely correct and pedantic, you have to expose three different ref-qualified versions of for_items. E.g.:
template <typename F>
void for_items(F&& f) & { for(auto& i : items) f(i); }
template <typename F>
void for_items(F&& f) const& { for(const auto& i : items) f(i); }
template <typename F>
void for_items(F&& f) && { for(auto& i : items) f(std::move(i)); }
The above code ensures const-correctness and allows elements to be moved when the something instance is a temporary.
Here is a proxy-based approach (though I'm not sure whether the new type meets the requirement of not being confusing).
template<class Container> class IterateOnlyProxy {
public:
IterateOnlyProxy(Container& c) : c(c) {}
typename Container::iterator begin() { return c.begin(); }
typename Container::iterator end() { return c.end(); }
private:
Container& c;
};
The proxy is used as a return type for the getElements() method,
class Foo {
public:
using Vec = std::vector<int>;
using Proxy = IterateOnlyProxy<Vec>;
Proxy& getElements() { return elementsProxy; }
private:
Vec elements{4, 5, 6, 7};
Proxy elementsProxy{elements};
};
and client code can iterate over the underlying container, but that's about it.
Foo foo;
for (auto element : foo.getElements())
std::cout << element << std::endl;
foo.getElements()[42]; // error: no match for ‘operator[]’
If you want to hide a vector field in your class but still do range based for-loop, you could add your own iterator based on vector::iterator.
A simple (and incomplete) example could be like:
#include <iostream>
#include <vector>
class Foo
{
public:
class iterator
{
public:
iterator(std::vector<int>::iterator n) : p(n) {}
bool operator==(iterator& rhs) { return p == rhs.p; }
bool operator!=(iterator& rhs) { return p != rhs.p; }
iterator& operator++() { p++; return *this; }
int& operator*() { return *p; }
private:
std::vector<int>::iterator p;
};
iterator begin() { return iterator(v.begin()); }
iterator end() { return iterator(v.end()); }
private:
std::vector<int> v {1, 2, 3, 4, 5};
};
int main() {
Foo foo;
for(auto y : foo) std::cout << y << std::endl;
return 0;
}
I'd like to call template<typename T> foo(T x) and manually handle these cases: T = std::vector<U>, T = std::string, T = any other case.
Here's what I wrote for that:
#include <iostream>
#include <vector>
#include <string>
template<typename T> void foo_impl(const std::string &data, std::string *) {
std::cout << "foo for std::string called\n";
}
template<typename T> void foo_impl(const T &data, T *) {
std::cout << "foo for general types called\n";
}
template<typename T> void foo_impl(const std::vector<T> &data, std::vector<T> *) {
std::cout << "foo for std::vector<T> called\n";
}
template<typename T> void foo(const T &data) {
foo_impl(data, static_cast<T*>(nullptr));
}
int main() {
int i = 1;
foo(i);
std::vector<int> a = {0, 1};
foo(a);
std::string s = "abcd";
foo<std::string>(s);
return 0;
}
However, foo(std::string x) is called as in case "T is any other type". How do I deal with it?
For template:
template<typename T> void foo(const T &data) {
std::cout << "foo for general types called\n";
}
Following is a specialization:
template<> void foo<>(const std::string &data) {
std::cout << "foo for std::string called\n";
}
but simple overload seems more appropriate:
void foo(const std::string &data) {
std::cout << "foo for std::string called\n";
}
As partial specialization is not possible for function, you have to make a overload for vector case:
template<typename T, typename Alloc> void foo(const std::vector<T, Alloc> &data) {
std::cout << "foo for std::vector<T, Alloc> called\n";
}
An alternative is to forward to a class/struct which can be (partially) specialized:
template <typename T>
struct foo_impl {
void operator (const T&) const
{
std::cout << "foo for general types called\n";
}
};
// specialization for std::string
template <>
struct foo_impl<std::string>
{
void operator (const T&) const
{
std::cout << "foo for std::string called\n";
}
};
// partial specialization for std::vector
template <typename T, typename A>
struct foo_impl<std::vector<T, A>>
{
void operator (const std::vector<T, A>&) const
{
std::cout << "foo for std::vector<T, A> called\n";
}
};
template <typename T>
void foo(const T& t)
{
foo_impl<T>{}(t);
}
T from template<typename T> void foo_impl(const std::string &data, std::string *) is non-deducible (that is, it's not used in the parameter list of the function), as such, it's not considered as a viable overload.
You can remove the template<typename T> part and make this overload a non-template:
void foo_impl(const std::string &data, std::string *) {
std::cout << "foo for std::string called\n";
}
It's not clear to me why you are using two layers of functions..
You can overload foo for std::string and std::vector<T>.
#include <iostream>
#include <vector>
#include <string>
template<typename T> void foo(const T &data) {
std::cout << "foo for general types called\n";
}
template <typename T> void foo(const std::vector<T> &data) {
std::cout << "foo for std::vector<T> called\n";
}
void foo(const std::string &data) {
std::cout << "foo for std::string called\n";
}
int main() {
int i = 1;
foo(i);
std::vector<int> a = {0, 1};
foo(a);
std::string s = "abcd";
foo(s);
return 0;
}
Output:
foo for general types called
foo for std::vector<T> called
foo for std::string called
I'm working on a project for school and need to sort some data. I've been given a vector of objects and I have to sort the objects (either in place or using an index) based on one of their properties. There are several different objects and several different properties that could it be sorted by. What's the best way to go about doing this?
Use std::sort and a functor. e.g:
struct SortByX
{
bool operator() const (MyClass const & L, MyClass const & R) { return L.x < R.x; }
};
std::sort(vec.begin(), vec.end(), SortByX());
The functor's operator() should return true if L is less than R for the sort order you desire.
There are several different objects and several different properties that could it be sorted by.
While the solution Erik posted is correct, this statement leads me to think that it's impractical at best if you are in fact planning to sort by multiple public data members of multiple classes in multiple ways in the same program, as each sorting method will require its own functor type.
I recommend the following abstraction:
#include <functional>
template<typename C, typename M, template<typename> class Pred = std::less>
struct member_comparer : std::binary_function<C, C, bool> {
explicit member_comparer(M C::*ptr) : ptr_{ptr} { }
bool operator ()(C const& lhs, C const& rhs) const {
return Pred<M>{}(lhs.*ptr_, rhs.*ptr_);
}
private:
M C::*ptr_;
};
template<template<typename> class Pred = std::less, typename C, typename M>
member_comparer<C, M, Pred> make_member_comparer(M C::*ptr) {
return member_comparer<C, M, Pred>{ptr};
}
Usage would look like:
#include <algorithm>
#include <string>
#include <vector>
struct MyClass {
int i;
std::string s;
MyClass(int i_, std::string const& s_) : i{i_}, s{s_} { }
};
int main() {
std::vector<MyClass> vec;
vec.emplace_back(2, "two");
vec.emplace_back(8, "eight");
// sort by i, ascending
std::sort(vec.begin(), vec.end(), make_member_comparer(&MyClass::i));
// sort by s, ascending
std::sort(vec.begin(), vec.end(), make_member_comparer(&MyClass::s));
// sort by s, descending
std::sort(vec.begin(), vec.end(), make_member_comparer<std::greater>(&MyClass::s));
}
This will work for any type with public data members, and will save a lot of typing if you need to sort your classes more than a couple of different ways.
Here is a variation that works with public member functions instead of public data members:
#include <functional>
template<typename C, typename M, template<typename> class Pred = std::less>
struct method_comparer : std::binary_function<C, C, bool> {
explicit method_comparer(M (C::*ptr)() const) : ptr_{ptr} { }
bool operator ()(C const& lhs, C const& rhs) const {
return Pred<M>{}((lhs.*ptr_)(), (rhs.*ptr_)());
}
private:
M (C::*ptr_)() const;
};
template<template<typename> class Pred = std::less, typename C, typename M>
method_comparer<C, M, Pred> make_method_comparer(M (C::*ptr)() const) {
return method_comparer<C, M, Pred>{ptr};
}
With usage like:
#include <algorithm>
#include <string>
#include <vector>
class MyClass {
int i_;
std::string s_;
public:
MyClass(int i, std::string const& s) : i_{i}, s_{s} { }
int i() const { return i_; }
std::string const& s() const { return s_; }
};
int main() {
std::vector<MyClass> vec;
vec.emplace_back(2, "two");
vec.emplace_back(8, "eight");
// sort by i(), ascending
std::sort(vec.begin(), vec.end(), make_method_comparer(&MyClass::i));
// sort by s(), ascending
std::sort(vec.begin(), vec.end(), make_method_comparer(&MyClass::s));
// sort by s(), descending
std::sort(vec.begin(), vec.end(), make_method_comparer<std::greater>(&MyClass::s));
}
Here is my version of the answer, just use a lambda function! It works, it uses way less code, and in my opinion it's elegant!
#include <algorithm>
#include <vector>
#include <string>
struct MyClass
{
int i;
std::string s;
MyClass(int i_, std::string const& s_) : i(i_), s(s_) { }
};
int main()
{
std::vector<MyClass> vec;
vec.push_back(MyClass(2, "two"));
vec.push_back(MyClass(8, "eight"));
// sort by i, ascending
std::sort(vec.begin(), vec.end(), [](MyClass a, MyClass b){ return a.i < b.i; });
// sort by s, ascending
std::sort(vec.begin(), vec.end(), [](MyClass a, MyClass b){ return a.s < b.s; });
// sort by s, descending
std::sort(vec.begin(), vec.end(), [](MyClass a, MyClass b){ return a.s > b.s; });
}
sort(v.begin(), v.end(), [](const Car* lhs, const Car* rhs) {
return lhs->getPassengers() < rhs->getPassengers();
});
EDIT: replacing with lambda_compare, because I'm a masochist:
You can also just create a helper that lets you specify which value to use via a lambda expression:
template <class F> class lambda_compare
{
public:
lambda_compare(F f_): f(f_) { }
template <class T> bool operator()(const T &lhs, const T &rhs) const
{ return f(lhs)<f(rhs); }
private:
F f;
};
template <class F> lambda_compare<F> make_lambda_compare(F f)
{ return f; }
...
std::sort(vec.begin(), vec.end(), make_lambda_compare([](const foo &value) { return value.member; }));