I'd like to write a class test that is able to store a function that is able to iterate through a collection of elements identified by the classic [first,last) iterator pair, that is:
template <typename T>
struct sum
{
template <typename I>
T operator()(I first, I last) const
{
T res = 0;
while (first != last)
{
res += *first;
++first;
}
return res;
}
};
//...
int main()
{
test<double> t;
t.set(sum<double>);
double a[] {1.,2.,3.};
std::cout << "Test (array) => " << t.call(a, a+3) << std::endl;
std::vector<double> v {1.,2.,3.};
std::cout << "Test (vector) => " << t.call(v.begin(), v.end()) << std::endl;
std::list<double> l {1.,2.,3.};
std::cout << "Test (list) => " << t.call(l.begin(), l.end()) << std::endl;
}
I thought to use std::function, but I've failed to do this as I wasn't able to declare the templated iterator pair.
A possible workaround is the following, which however only works with plain arrays (e.g., double[] or double*, like the above variable a), but not with other containers (e.g., like the above variables v and l):
template <typename T>
class test
{
public:
template <typename F>
void set(F f)
{
f_ = f;
}
template <typename I>
T call(I first, I last) const
{
return f_(first, last);
}
private:
std::function<T(T*,T*)> f_;
};
Any idea on how can I get the correct behavior?
NOTE: I'm compiling with GCC 4.9.2 --std=c++11
Thank you very much.
What you want is really to be able to construct a:
std::function<T(FwdIter<T>, FwdIter<T>)>
where FwdIter<T> is some type-erased class that satsifes the ForwardIterator concept and is dereferenced to a T. For that, check out the Boost.TypeErasure library, where we can do:
#include <boost/type_erasure/any.hpp>
#include <boost/type_erasure/operators.hpp>
#include <boost/mpl/vector.hpp>
using namespace boost::type_erasure;
template <typename T>
using FwdIter = any<
boost::mpl::vector<
copy_constructible<>,
incrementable<>,
dereferenceable<T>,
equality_comparable<>
>>;
With that and your definition of sum, I can do:
std::function<int(FwdIter<int>, FwdIter<int>)> f = sum<int>{};
std::vector<int> v = {1, 2, 3, 4, 5};
std::cout << f(v.begin(), v.end()) << std::endl; // prints 15
In your test<T>, you could just have a std::function<T(FwdIter<T>, FwdIter<T>)> member as desired.
I've tried to work on an alternative solution.
Essentially, the user function is wrapped inside a holder holder which fix the function signature to T(const std::vector<T>&). With respect to #Barry's solution (the one I've accepted), this doesn't require external libraries. However it suffers of performance issues due to the construction of the vector object at runtime. Also, and more importantly, as pointed out by #Barry, this solution imposes artificial requirements on T (like T must be copyable).
Here is it:
template <typename T,typename F>
class holder
{
public:
holder(F f) : f_(f) { }
T operator()(const std::vector<T>& v) const
{
return f_(v.begin(), v.end());
}
private:
F f_;
};
template <typename T>
class test_v2
{
public:
template <typename F>
void set(F f)
{
f_ = holder<T,F>(f);
}
template <typename I>
T call(I first, I last) const
{
return f_(std::vector<T>(first, last));
}
private:
std::function<T(const std::vector<T>&)> f_;
};
Why not stoke the functor instead, something like:
template <typename T>
class test
{
public:
template <typename I>
auto call(I first, I last) const
-> decltype(T()(first, last))
{
return T()(first, last);
}
};
And use it:
test<sum<double>> t;
Live example
Related
I have a pretty specific situation where I'm feeding a bunch of data to a hasher-like class. In particular, one data type that I use has a member whose type depends on the supertype's type parameter. Long story short, here's a piece of code that illustrates this behaviour :
#include <assert.h>
#include <iostream>
#include <string>
#include <type_traits>
#include <utility>
#include <vector>
// Some dummy priority structs to select overloads
struct priority0 { };
struct priority1 : priority0 { };
// This is the hasher-like function
struct Catcher
{
// Ideally we feed everything to this object through here
template <typename T> Catcher& operator<<(const T& v)
{
add(v, priority1{}); // always attempt to call the highest-priority overload
return *this;
}
// For floating-point data types
template <typename T> auto add(const T& v, priority1) -> std::enable_if_t<std::is_floating_point_v<T>, void>
{
std::cout << "caught float/double : " << v << std::endl;
}
// For ranges
template <class T> auto add(const T& range, priority1) -> decltype(begin(range), end(range), void())
{
for(auto const& v : range)
*this << v;
}
// For chars
void add(char c, priority1)
{
std::cout << c;
std::cout.flush();
}
// When everything else fails ; ideally should never happen
template <typename T> void add(const T& v, priority0)
{
assert(false && "should never happen");
}
};
// The one data type. Notice how the primary template and the
// specialization have a `range` member of different types
template <class T> struct ValueOrRange
{
struct Range
{
T min;
T max;
};
Range range;
T value;
};
template <> struct ValueOrRange<std::string>
{
std::vector<std::string> range;
std::string value;
};
// Overload operator<< for Catcher outside of the
// class to allow for processing of the new data type
// Also overload that for `ValueOrRange<T>::Range`. SFINAE should make sure
// that this behaves correctly (?)
template <class T> Catcher& operator<<(Catcher& c, const typename ValueOrRange<T>::Range& r)
{
return c << r.min << r.max;
}
template <class T> Catcher& operator<<(Catcher& c, const ValueOrRange<T>& v)
{
return c << v.range << v.value;
}
int main(int argc, char *argv[])
{
ValueOrRange<std::string> vor1{{}, "bleh"};
ValueOrRange<float> vor2{{0.f, 1.f}, 0.5f};
Catcher c;
c << vor1; // works fine, displays "bleh"
c << vor2; // fails the assert in Catcher::add(const T&, priority0) with T = ValueOrRange<float>::Range
return 0;
}
While the line c << vor1 gets resolved correctly through the various overloads and has the intended effect, the second line c << vor2 fails the assert.
What I want to happen : c << vor2 calls Catcher& operator<<(Catcher& s, const ValueOrRange<float>& v), which in turn calls Catcher& operator<<(Catcher& s, const typename ValueOrRange<float>::Range& r)
What does happen : instead of Catcher& operator<<(Catcher& s, const typename ValueOrRange<float>::Range& r), it is Catcher& Catcher::operator<<(const T& v) with T = typename ValueOrRange<float>::Range that is called, and thus the assert fails.
Worthy of note is that this same code has the intended effect on MSVC, and fails the assert on GCC.
Any idea on how I should fix that ?
Thanks to feedback from Igor Tandetnik, I got rid of the ::Range-specific overload and simply went for checking std::is_same_v<T, std::string>. A little less modular than I'd like, but it'll do the trick.
// A single function will do the trick
template <class T> Catcher& operator<<(Catcher& c, const ValueOrRange<T>& v)
{
if constexpr (std::is_same_v<T, std::string>)
c << v.range;
else
c << v.range.min << v.range.max;
return c << v.value;
}
In Catcher& operator<<(Catcher& c, const typename ValueOrRange<T>::Range& r), T in non deducible.
One work around would be friend function:
template <class T> struct ValueOrRange
{
struct Range
{
T min;
T max;
friend Catcher& operator<<(Catcher& c, const Range& r)
{
return c << r.min << r.max;
}
};
Range range;
T value;
};
Demo
I am making function Fold, which can accept different classes, e.g. Sum, which specify the type of operation done.
#include <iostream>
#include <vector>
#include <list>
template <typename T>
struct Sum {
public:
auto operator() (T init, std::list<int>::const_iterator first,
std::list<int>::const_iterator last) {
for (auto it = first; it != last; ++it) {
init += *it;
}
return init;
}
};
template <typename Iterat, typename T, typename Operator>
T Fold(Iterat first, Iterat last, T init, Operator func) {
return func(init, first, last);
}
int main() {
std::list<int> a{1, 2, 3, 6};
std::cout << Fold(a.cbegin(), a.cend(), 0, Sum()) << std::endl;
return 0;
}
However, when I ran the code, I got the mistake "no viable constructor or deduction guide for deduction of template arguments of 'Sum'"
The mistake can be managed two ways:
If I use "int" instead of "template T" in class sum.
If I specify in main() the type I want to use like:
Fold(a.cbegin(), a.cend(), 0, Sum<int>())
Are there other ways to do something with this mistake? Neither of the two solutions I showed higher are suitable for my task
Template arguments are deduced from the (function) arguments. Since Sum does not have arguments, the template arguments cannot be deduced. This is explained here.
All is not lost, however. Sum, as a class, does not use the template parameters. Only the operator() method does. Therefore, you can put template only the operator() method, and leave Sum as a non-template class.
For instance:
struct Sum {
public:
template <typename T>
auto operator() (T init, std::list<int>::const_iterator first,
std::list<int>::const_iterator last) {
for (auto it = first; it != last; ++it) {
init += *it;
}
return init;
}
};
I would also go as far as templating the iterator as well, like you did with Fold. The complete code example, with some additional usage examples, is:
#include <functional>
#include <iostream>
#include <list>
#include <vector>
struct Sum {
public:
template <typename T, typename Iterat>
auto operator() (T init, Iterat first, Iterat last) {
for (auto it = first; it != last; ++it) {
init += *it;
}
return init;
}
};
template <typename Iterat, typename T, typename Operator>
T Fold(Iterat first, Iterat last, T init, Operator func) {
return func(init, first, last);
}
int main() {
std::list<int> a{1, 2, 3, 6};
std::cout << Fold(a.cbegin(), a.cend(), 0, Sum()) << std::endl;
// init is a float. While the iterators return int.
std::cout << Fold(a.cbegin(), a.cend(), 0.5 , Sum()) << std::endl;
std::list<std::string> b{"1", "2", "3", "6"};
std::cout << Fold(b.cbegin(), b.cend(), std::string(""), Sum()) << std::endl;
return 0;
}
I am trying to write a simple template function that prints every element of some container, without using for loops. So far, I have
#include <iostream>
#include <vector>
#include <algorithm>
template <typename T> void print_with_space(T x){
std::cout << x << ' ';
}
template <typename T> void print_all(T beg, T end){
std::for_each(beg, end, print_with_space<int>);
std::cout << '\n';
}
int main(){
int a[] = {1, 2, 3};
std::vector<int> v(a, a+3);
print_all(v.begin(), v.end());
return 0;
}
The code compiles and runs, but only because I put print_with_space<int> inside the implementation of print_all. I would like to just have print_with_space there for obvious reasons, but then the code doesn't compile. How do I do this?
You can use:
std::for_each(beg, end, [](const typename T::value_type& value) {
print_with_space(value);
});
T is of type std::vector<>::iterator, which is a RandomAccessIterator. Every RandomAcessIterator has a underlying type, which is exposed by value_type.
So, if you pass std::vector<int>::iterator, std::vector<int>::iterator::value_type would be an int.
Now that you have the type, you can make a lambda, which will get executed for every iteration.
In C++14, you can even do:
//'auto' automatically deduces the type for you
std::for_each(beg, end, [](const auto& value) {
print_with_space(value);
});
Another option:
template <typename T> void print_all(T beg, T end) {
std::for_each(beg, end, print_with_space<decltype(*beg)>);
std::cout << '\n';
}
Alternative for C++03:
#include <iterator>
template <typename T> void print_all(T beg, T end)
{
typedef typename std::iterator_traits<T>::value_type val_t;
std::for_each(beg, end, print_with_space<val_t>);
std::cout << '\n';
}
The most flexible solution, which will work with all versions of c++, is to make print_with_space a function object.
This confers a number of advantages:
no need to specify template type at call site.
no need to fiddle around with manual type deduction.
partial specialisation can be achieved by having the functor defer to a templated free function.
Such as:
#include <iostream>
#include <iomanip>
#include <vector>
#include <algorithm>
// basic implementation
template<class T> void impl_print_with_space(const T& x)
{
std::cout << x << ' ';
}
// what about special handling for strings?
template<class C, class Ch, class Alloc>
void impl_print_with_space(const std::basic_string<C, Ch, Alloc>& x)
{
std::cout << std::quoted(x) << ' ';
}
// functor
struct print_with_space
{
template<class T> void operator()(const T& x) const
{
impl_print_with_space(x);
}
};
template <typename Iter> void print_all(Iter beg, Iter end)
{
std::for_each(beg, end, print_with_space());
std::cout << '\n';
}
int main(){
int a[] = {1, 2, 3};
std::vector<int> v(a, a+3);
print_all(v.begin(), v.end());
auto b = std::vector<std::string> { "hello", "world" };
print_all(b.begin(), b.end());
return 0;
}
I have a template class where each template argument stands for one type of value the internal computation can handle. Templates (instead of function overloading) are needed because the values are passed as boost::any and their types are not clear before runtime.
To properly cast to the correct types, I would like to have a member list for each variadic argument type, something like this:
template<typename ...AcceptedTypes> // e.g. MyClass<T1, T2>
class MyClass {
std::vector<T1> m_argumentsOfType1;
std::vector<T2> m_argumentsOfType2; // ...
};
Or alternatively, I'd like to store the template argument types in a list, as to do some RTTI magic with it (?). But how to save them in a std::initializer_list member is also unclear to me.
Thanks for any help!
As you have already been hinted, the best way is to use a tuple:
template<typename ...AcceptedTypes> // e.g. MyClass<T1, T2>
class MyClass {
std::tuple<std::vector<AcceptedTypes>...> vectors;
};
This is the only way to multiply the "fields" because you cannot magically make it spell up the field names. Another important thing may be to get some named access to them. I guess that what you're trying to achieve is to have multiple vectors with unique types, so you can have the following facility to "search" for the correct vector by its value type:
template <class T1, class T2>
struct SameType
{
static const bool value = false;
};
template<class T>
struct SameType<T, T>
{
static const bool value = true;
};
template <typename... Types>
class MyClass
{
public:
typedef std::tuple<vector<Types>...> vtype;
vtype vectors;
template<int N, typename T>
struct VectorOfType: SameType<T,
typename std::tuple_element<N, vtype>::type::value_type>
{ };
template <int N, class T, class Tuple,
bool Match = false> // this =false is only for clarity
struct MatchingField
{
static vector<T>& get(Tuple& tp)
{
// The "non-matching" version
return MatchingField<N+1, T, Tuple,
VectorOfType<N+1, T>::value>::get(tp);
}
};
template <int N, class T, class Tuple>
struct MatchingField<N, T, Tuple, true>
{
static vector<T>& get(Tuple& tp)
{
return std::get<N>(tp);
}
};
template <typename T>
vector<T>& access()
{
return MatchingField<0, T, vtype,
VectorOfType<0, T>::value>::get(vectors);
}
};
Here is the testcase so you can try it out:
int main( int argc, char** argv )
{
int twelf = 12.5;
typedef reference_wrapper<int> rint;
MyClass<float, rint> mc;
vector<rint>& i = mc.access<rint>();
i.push_back(twelf);
mc.access<float>().push_back(10.5);
cout << "Test:\n";
cout << "floats: " << mc.access<float>()[0] << endl;
cout << "ints: " << mc.access<rint>()[0] << endl;
//mc.access<double>();
return 0;
}
If you use any type that is not in the list of types you passed to specialize MyClass (see this commented-out access for double), you'll get a compile error, not too readable, but gcc at least points the correct place that has caused the problem and at least such an error message suggests the correct cause of the problem - here, for example, if you tried to do mc.access<double>():
error: ‘value’ is not a member of ‘MyClass<float, int>::VectorOfType<2, double>’
An alternate solution that doesn't use tuples is to use CRTP to create a class hierarchy where each base class is a specialization for one of the types:
#include <iostream>
#include <string>
template<class L, class... R> class My_class;
template<class L>
class My_class<L>
{
public:
protected:
L get()
{
return val;
}
void set(const L new_val)
{
val = new_val;
}
private:
L val;
};
template<class L, class... R>
class My_class : public My_class<L>, public My_class<R...>
{
public:
template<class T>
T Get()
{
return this->My_class<T>::get();
}
template<class T>
void Set(const T new_val)
{
this->My_class<T>::set(new_val);
}
};
int main(int, char**)
{
My_class<int, double, std::string> c;
c.Set<int>(4);
c.Set<double>(12.5);
c.Set<std::string>("Hello World");
std::cout << "int: " << c.Get<int>() << "\n";
std::cout << "double: " << c.Get<double>() << "\n";
std::cout << "string: " << c.Get<std::string>() << std::endl;
return 0;
}
One way to do such a thing, as mentioned in πάντα-ῥεῖ's comment is to use a tuple. What he didn't explain (probably to save you from yourself) is how that might look.
Here is an example:
using namespace std;
// define the abomination
template<typename...Types>
struct thing
{
thing(std::vector<Types>... args)
: _x { std::move(args)... }
{}
void print()
{
do_print_vectors(std::index_sequence_for<Types...>());
}
private:
template<std::size_t... Is>
void do_print_vectors(std::index_sequence<Is...>)
{
using swallow = int[];
(void)swallow{0, (print_one(std::get<Is>(_x)), 0)...};
}
template<class Vector>
void print_one(const Vector& v)
{
copy(begin(v), end(v), ostream_iterator<typename Vector::value_type>(cout, ","));
cout << endl;
}
private:
tuple<std::vector<Types>...> _x;
};
// test it
BOOST_AUTO_TEST_CASE(play_tuples)
{
thing<int, double, string> t {
{ 1, 2, 3, },
{ 1.1, 2.2, 3.3 },
{ "one"s, "two"s, "three"s }
};
t.print();
}
expected output:
1,2,3,
1.1,2.2,3.3,
one,two,three,
There is a proposal to allow this kind of expansion, with the intuitive syntax: P1858R1 Generalized pack declaration and usage. You can also initialize the members and access them by index. You can even support structured bindings by writing using... tuple_element = /*...*/:
template <typename... Ts>
class MyClass {
std::vector<Ts>... elems;
public:
using... tuple_element = std::vector<Ts>;
MyClass() = default;
explicit MyClass(std::vector<Ts>... args) noexcept
: elems(std::move(args))...
{
}
template <std::size_t I>
requires I < sizeof...(Ts)
auto& get() noexcept
{
return elems...[I];
}
template <std::size_t I>
requires I < sizeof...(Ts)
const auto& get() const
{
return elems...[I];
}
// ...
};
Then the class can be used like this:
using Vecs = MyClass<int, double>;
Vecs vecs{};
vecs.[0].resize(3, 42);
std::array<double, 4> arr{1.0, 2.0, 4.0, 8.0};
vecs.[1] = {arr.[:]};
// print the elements
// note the use of vecs.[:] and Vecs::[:]
(std::copy(vecs.[:].begin(), vecs.[:].end(),
std::ostream_iterator<Vecs::[:]>{std::cout, ' '},
std::cout << '\n'), ...);
Here is a less than perfectly efficient implementation using boost::variant:
template<typename ... Ts>
using variant_vector = boost::variant< std::vector<Ts>... >;
template<typename ...Ts>
struct MyClass {
using var_vec = variant_vector<Ts...>;
std::array<var_vec, sizeof...(Ts)> vecs;
};
we create a variant-vector that can hold one of a list of types in it. You have to use boost::variant to get at the contents (which means knowing the type of the contents, or writing a visitor).
We then store an array of these variant vectors, one per type.
Now, if your class only ever holds one type of data, you can do away with the array, and just have one member of type var_vec.
I cannot see why you'd want one vector of each type. I could see wanting a vector where each element is one of any type. That would be a vector<variant<Ts...>>, as opposed to the above variant<vector<Ts>...>.
variant<Ts...> is the boost union-with-type. any is the boost smart-void*. optional is the boost there-or-not.
template<class...Ts>
boost::optional<boost::variant<Ts...>> to_variant( boost::any );
may be a useful function, that takes an any and tries to convert it to any of the Ts... types in the variant, and returns it if it succeeds (and returns an empty optional if not).
Let's assume, that a class can use the following data-types to pass data to and from it:
std::vector<complex> // where "complex" is a struct
and
std::vector DOUBLE or INT or FLOAT or STRING
If the user passes through a std::vector<double> this implies that a calculation has already been carried out and therefore only a small process has to be completed. If the user, however, passes through std::vector<complex> this means that the calculation has to be carried out.
In a class I can do the following:
class Foo {
template<typename T>
Foo(T begin, T end)
{
this->transform(begin, end);
}
template<typename T>
void transform(T begin, T end)
{
std::cout << "This has been called";
}
};
But this will have to still invoke me having to have a data member of one specific type and always assume they are doing that.
For example, is it possible to override the function transform for 2 different cases, and, have the constructor decide which method to call depending on type of data being passed to the constructor.
It would work something like this:
int main()
{
std::vector<double> vals = {1,1,1,1,1,1,1,1};
Foo(std::begin(vals), std::end(vals)); // this will call the method that handles dbls
std::vector<complex> vals = {};
Foo(std::begin(vals), std::end(vals)); // This will call the method that handles complex numbers
}
I hope this makes sense
This can be solved through template specialization.
Considere the following function:
template<typename T>
void Foo(T arg)
{
std::cout << "General" << std::endl;
}
We can now specialize this function for char types, this means providing another implementation for those types:
template<>
void Foo(char arg)
{
std::cout << arg << std::endl;
}
Notice that the template<> can be omitted in this case.
If we now call our functions like this:
Foo(1);
Foo('a');
The output will be:
General
a
One way would be tag dispatching (I used struct X instead of complex here):
#include <iostream>
#include <vector>
#include <iterator>
struct X {};
struct Foo {
template<typename T>
Foo(T begin, T end)
{
transform(begin, end, typename std::iterator_traits<T>::value_type());
}
template<typename T, typename U>
void transform(T begin, T end, U) // third parameter is unused and serves as a tag
{
std::cout << "floating point\n";
}
template<typename T>
void transform(T begin, T end, X) // same here
{
std::cout << "X\n";
}
};
int main()
{
std::vector<double> v1 = {1,1,1,1,1,1,1,1};
Foo(std::begin(v1), std::end(v1)); // floating point
std::vector<X> v2 = {};
Foo(std::begin(v2), std::end(v2)); // X
}