Im trying to create a class as container-wrapper, something like this
#include <vector>
template <typename T, typename U>
class Test {
T<U> list;
};
int main() {
Test<std::vector, int> test;
}
But this wont work. I know it will work when I use it like this
#include <vector>
template <typename T>
class Test {
T list;
};
int main() {
Test<std::vector<int>> test;
}
but how would I write my insert?
template <typename T>
class Test {
T list;
public:
void insert(??? element) {
...
}
};
TIA, Narase
The easiest one would be
template <typename T>
class Test {
....
void insert(const typename T::value_type& element);
And/or, for completeness and move semantics compliance:
void insert(typename T::value_type&& element);
But this wont work.
With your first snippet of Test, since std::vector has two template parameters, value_type and allocator_type, we must specify the existence of these template parameters in the declaration of T using template template parameters as follows.
Here I use variadic one and then T<U...> becomes legal for
T = std::vector and compilation errors are removed.
how would I write my insert?
The following code also shows an implementation example of Test::insert.
Since this method can accept both lvalue and rvalue references in C++11 and over, here I apply the forwarding reference (which is what Scott Meyers calls universal reference,) to it.
In this approach, we does not need to specify the value type of Test::list in the Test::insert definition and passing wrong types to Test::insert causes compilation errors.
If you need the value type of std::vector, the member type std::vector::value_type is available:
template <template<class...> class T, class ...U>
class Test
{
T<U...> list;
public:
template<class ...V>
void insert(V&& ...element) {
list.insert(std::forward<V>(element)...);
}
typename T<U...>::iterator begin() noexcept {
return list.begin();
}
typename T<U...>::iterator end() noexcept {
return list.end();
}
using value_type = typename T<U...>::value_type;
};
This is an usage example with std::vector:
DEMO (std::vector)
static_assert(
std::is_same<Test<std::vector, int>::value_type, int>::value, "oops!"); // OK.
Test<std::vector, int> test; // OK
test.insert(test.end(), 11);
test.insert(test.end(), 99);
for(auto it = test.begin(); it != test.end(); ++it){
std::cout << *it << std::endl;
}
As another example, this wrapper class also works with std::map as follows:
DEMO (std::map)
static_assert(
std::is_same<Test<std::map, int, int>::value_type, std::pair<const int, int>>::value, "oops!"); // OK.
Test<std::map, int, int> test; // OK
test.insert(std::make_pair(1, 11));
test.insert(std::make_pair(2, 99));
for(auto it = test.begin(); it!= test.end(); ++it){
std::cout << it->first << ", " << it->second << std::endl;
}
Finally, this is a fixed version of your second snippet:
DEMO (std::vector)
DEMO (std::set)
template <class T>
class Test
{
T list;
public:
template<class ...V>
void insert(V&& ...element) {
list.insert(std::forward<V>(element)...);
}
typename T::iterator begin() noexcept {
return list.begin();
}
typename T::iterator end() noexcept {
return list.end();
}
using value_type = typename T::value_type;
};
Related
I want to write a function that takes a generic container with any type and prints it.
Let's leave for a moment that it won't work for some associative containers and focus on the issue:
template<template<typename> typename Cont, typename T>
void print(const Cont<T>& cont)
{
for (const auto it : cont)
{
cout << it << " ";
}
cout << endl;
}
int main()
{
vector<string> v;
print(v);
}
The error states:
error C2672: 'print': no matching overloaded function found
error C3207: 'print': invalid template argument for 'Cont', class template expected
Can anyone please explain why the compiler cannot deduce the types here?
Even when I explicitly state print<vector<string>>(v)?
std::vector has more than one class-template-args.
template<
class T, // -----------> you have mentioned!
class Allocator = std::allocator<T> // -----> this didn't!
> class vector;
But you have provided only one. This is the reason for the no matching overloaded compiler error.
In order to fix the issue, you need to provide the variadic args in the template template arg.
template<template<typename...> typename Cont, typename T>
// ^^^^^^^^^^^^^^^^^^^^
void print(const Cont<T>& cont)
{
for (const auto& it : cont) {
std::cout << it << " ";
}
std::cout << std::endl;
}
(See a demo)
However, you could have done this simply
template <typename Cont>
void print(const Cont& cont)
{
// ...
}
Or like the standard way, passing the begin and end iterator of the container to the function
#include <algorithm> // std::copy
#include <iterator> // std::iterator_traits
template<typename Iterator>
constexpr void print(const Iterator begin, const Iterator end) noexcept
{
using ValueType = typename std::iterator_traits<Iterator>::value_type;
std::copy(begin, end, std::ostream_iterator<ValueType>(std::cout, " "));
std::cout << "\n";
}
and call it like
print(v.begin(), v.end());
std::vector is defined as
template<
class T,
class Allocator = std::allocator<T>
> class vector;
std::vector is a class template with two template parameters. It does not match
the template template parameter of your function.
Change it to
template <typename Cont>
void print(const Cont& cont)
{
for (const auto& elem : cont) {
std::cout << elem << " ";
}
std::cout << std::endl;
}
You can deduce T from the container, if that is necessary.
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
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).
I have a little problem and I'm working on it for several hours but can't find a solution. Hope you will help me.
Here is my class:
#include <iostream>
#include <iterator>
template <typename T> class Array{
private:
size_t size;
T *newArray;
public:
class Iterator:public std::iterator<std::output_iterator_tag, T>{
T *p;
public:
Iterator(T*x):p(x){}
T& operator*() {return *p;}
};
Array (size_t size = 10): size(size), newArray(new T[size]){};
Iterator begin(){return (Iterator(newArray));}
T printBegin(typename Array<T>::Iterator it){ return *it;}
template <typename E>
T printBegin(typename Array<E>::Iterator it){ return (T)*it;}
};
And here is Main:
using namespace std;
int main(){
Array<int> x;
Array<int> y;
cout << y.printBegin(x.begin()); // prints 0 OK
Array<double> p;
// cout << p.printBegin(x.begin());
return 0;
}
The first cout works fine but the line that is commented gives this : error: no matching function for call to ‘Array<double>::printBegin(Array<int>::Iterator)’
I don't understand because the last line in my Array class matches (normally) for this function call
The problem is that you want to deduce the E in Array<E>::Iterator from x.begin() that is an Array<int>::Iterator. But that is simply not possible.
Your best option is probably to write:
template <typename IT>
T printBegin(IT it){ return (T)*it;}
If, for any reason, you need to use the E type, then it is better to add a nested typedef:
class Iterator:public std::iterator<std::output_iterator_tag, T>{
public:
typename T array_member_type;
//...
};
And then:
template <typename IT>
T printBegin(IT it){
typedef typename IT::array_member_type E;
return (T)*it;
}
Wait! Your iterator derives from std::iterator so the typedef already exists. No need to redefine:
template <typename IT>
T printBegin(IT it){
typedef typename IT::value_type E;
return (T)*it;
}
Your question is very similar to another question about template deduction.
The compiler cannot deduct the type E from Array<E>::Iterator. Why should it be able to? Two different types E could share the same iterator type.
What you are really saying to the compiler is:
"Is there a type "E" for which Array<E>::Iterator is this type?"
I need a function template that accepts two iterators that could be pointers. If the two arguments are random_access iterators I want the return type to be an object of
std::iterator<random_access_iterator_tag, ...> type
else a
std::iterator<bidirectional_iterator_tag, ...> type.
I also want the code to refuse
compilation if the arguments are neither a bidirectional iterator, nor a pointer. I cannot have dependency on third party libraries e.g. Boost
Could you help me with the signature of this function so that it accepts bidirectional iterators as well as pointers, but not say input_iterator, output_iterator, forward_iterators.
One partial solution I can think of is the following
template<class T>
T foo( T iter1, T iter2) {
const T tmp1 = reverse_iterator<T>(iter1);
const T tmp2 = reverse_iterator<T>(iter2);
// do something
}
The idea is that if it is not bidirectional the compiler will not let me construct a reverse_iterator from it.
Here's an example with enable_if based on iterator tags. The substitution fails if the given T doesn't have a iterator_category typedef and so that overload isn't considered during overload resolution.
Since you can't use C++11, see the reference pages for enable_if and is_same to see how you can implement it by yourself.
#include <iterator>
#include <type_traits>
#include <iostream>
#include <vector>
#include <list>
template<typename T>
typename
std::enable_if<
std::is_same<
typename T::iterator_category,
std::bidirectional_iterator_tag
>::value,
T
>::type
foo(T it)
{
std::cout << "bidirectional\n";
return it;
}
template<typename T>
typename
std::enable_if<
std::is_same<
typename T::iterator_category,
std::random_access_iterator_tag
>::value,
T
>::type
foo(T it)
{
std::cout << "random access\n";
return it;
}
// specialization for pointers
template<typename T>
T* foo(T* it)
{
std::cout << "pointer\n";
return it;
}
int main()
{
std::list<int>::iterator it1;
std::vector<int>::iterator it2;
int* it3;
std::istream_iterator<int> it4;
foo(it1);
foo(it2);
foo(it3);
//foo(it4); // this one doesn't compile, it4 is an input iterator
}
Live example.
As per #JonathanWakely's comment, we can get rid of specialization for pointers if we use std::iterator_traits. The typename T::iterator_category part then becomes
typename std::iterator_traits<T>::iterator_category
a bit simpler than previous answer, no dependency on std::enable_if:
namespace detail
{
template<class T>
T do_foo(T iter1, T iter2, std::random_access_iterator_tag t)
{
cout << "do_foo random_access" << endl;
return iter1;
}
template<class T>
T do_foo(T iter1, T iter2, std::bidirectional_iterator_tag t)
{
cout << "do_foo bidirectional" << endl;
return iter1;
}
}
template<class T>
void foo(T iter1, T iter2)
{
typename std::iterator_traits<T>::iterator_category t;
detail::do_foo(iter1, iter2, t);
}
int main (int argc, const char * argv[])
{
std::vector<int> v;
foo(v.begin(), v.end());
std::list<int> l;
foo(l.begin(), l.end());
return 0;
}
The solution also supports other iterator_categories derived from std::random_access_iterator_tag or std::bidirectional_iterator_tag (should there be any), while std::same<> checks for strict category equality.