I created a read only iterator which allows me to use it in a for loop more conveniently then with the std iterators, similar to what boost does with the FOREACH (not as good but good enough :))
Now it looks like this:
for(ReadOnylIterator<MyClass *> class = parent.getIterator(); class.end(); ++class)
class->function();
The problem that I have now is, that I must implement a function on the parent which returns the iterator. Since the std containers have all the same syntax, I was wondering if it is possible to define a copy constructor/assignment operator on the Iterator that accepts any of the std:: containers and creates the copy itself, instead of requiring the class to return it.
Of course I want to avoid having to define all of them myself like as there are lots of them:
ReadOnlyIterator<T> &operator=(std::list<T> const &v)
ReadOnlyIterator<T> &operator=(std::vector<T> const &v)
...
Is there a way to do this? When I look at the source of the vector I don't see a common base class, so I think it might not be posssible.
I don't understnad why the assignment operator doesn't work.
In my code I test it like this:
std::vector<SimpleClass *>t;
ReadOnlyIterator<SimpleClass *> &it = t;
And I get
error C2440: 'initializing' : cannot convert from 'std::vector<_Ty>' to 'ReadOnlyIterator<T> &'
If I understand you correctly, this should work:
#include <type_traits>
template <typename Container>
typename std::enable_if<std::is_same<T, typename Container::value_type>::value, ReadOnlyIterator<T>&>::type operator= (const Container &v);
The above code uses C++11. If you don't have access to that, you could use the equivalent functionality from Boost.
Live example
In case you can use neither C++11 nor Boost, you can code the necessary classes yourself:
template <typename T, typename U>
struct is_same
{
enum { value = 0 };
};
template <typename T>
struct is_same<T, T>
{
enum { value = 1 };
};
template <bool, typename>
struct enable_if
{};
template <typename T>
struct enable_if<true, T>
{
typedef T type;
};
To use this in a constructor, define it like this:
template <typename Container>
ReadOnlyIterator(const Container &v, typename enable_if<is_same<T, typename Container::value_type>::value, void>::type * = 0) {}
Live example
I'm sorry but no, this is not possible given that the containers don't have common base classes. You'll have to write an operator for each container, Sad news !
Although if the behavior of the operator functions is always the same, you could just make a macro that contains the code, and copy paste it for every container type ^_^
Related
I try to implement the copy constructor of my std compatible custom iterator for a custom container.
The container looks something like this:
template <typename T, Alloc>
class container {
template <typename ValueType>
class raw_iterator;
...
using value_type = T;
...
using iterator = raw_iterator<value_type>
using const_iterator = raw_iterator<const value_type>
...
}
The raw_iterator looks something like this:
template <typename T, Alloc>
template <typename ValueType>
class container<T, Alloc>::raw_iterator {
...
}
If i'm right, I have to implement a copy constructor for both, the iterator and const_iterator, such that the iterators can be copied to the same type and a normal iterator can be copied into a const_iterator.
How can this be achieved?
PS: I have to provide some functionality in the copy constructor, so i cant use an implizit generated constructor.
You can create an implicit constructor for the const_iterator which takes an iterator as argument. Then everything will "just work".
Here's an example of what I think you want:
#include <type_traits>
template <typename ValueType>
class raw_iterator {
public:
// Typedefs
using non_const_value_type = std::remove_const_t<ValueType>;
using const_value_type = std::add_const_t<non_const_value_type>;
// Constructor - Need extra template argument here to allow SFINAE to work.
template <class U = ValueType,
std::enable_if_t<std::is_same<U, const_value_type>::value, int> = 0>
raw_iterator (raw_iterator<non_const_value_type> const & other) {
// Do stuff.
}
private:
// Friends - Make raw_iterator<X> friend of raw_iterator<X const>
friend std::conditional_t<
std::is_same<ValueType, non_const_value_type>::value,
raw_iterator<const_value_type>, void
>;
};
There's a conditional constructor taking an raw_iterator<AnythingNonConst> which only exists if the raw_iterator's own temple type is AnythingConst.
Furthermore, raw_iterator<AnythingNonConst> is a friend of raw_iterator<AnythingConst>, but not the other way around. So you can copy whatever members you want in the conditional constructor.
Here's an online example: https://wandbox.org/permlink/8gDzHyheIrpsTL5y.
I'm trying to learn a bit about templates and metafunctions, namely std::enable_if. I'm making a menu system for our school assignments (extracurricular, mind you), and need a way of getting input from the user. I'd like to define a template class for various types of input - something used along the lines of:
std::string userInput = Input<std::string>("What's your name?").Show();
float userHeight = Input<float>("How tall are you?").Show();
I'd like to (and I'm sure there are reasons not to, but nevertheless) do this generalized sort of conversion using a std::stringstream: get input from user, feed into SS, extract into variable of type T.
It's easy enough to see if the conversion failed during runtime, but I'd like to use std::enable_if to prevent people from using my Input<> class for cases where conversion is impossible, say:
std::vector<Boats> = Input<std::vector<>>("Example").Show();
Obviously a std::stringstream cannot convert a string to a vector, so it will always fail.
My question is this:
Can I format an std::enable_if clause to ONLY allow instantiation of my template class for the types listed above? Alternatively, is there a better way to go about it? Have I got things completely the wrong way around?
What I've done so far
I believe I have found a list of allowed types that std::stringstream can "convert" a string into:
http://www.cplusplus.com/reference/istream/istream/operator%3E%3E/
I've been using std::enable_if like this up until this point:
template <typename T, typename = typename
std::enable_if<std::is_arithmetic<T>::value, T>::type>
However, now I'd like to extend it to allow not only arithmetic values, but all values supported by the sstream >> operator.
If you prefer to use a SFINAE with a class template parameter, then you want
template <
typename T,
typename = decltype(std::declval<std::istringstream &>() >> std::declval<T &>(), void())
>
class Input /*...*/
I think that you are trying to use std::enable_if for something which doesn't require it. If your template function already relies on operator<< applied on a generic type T, then compilation will fail in any case if the operator is not specialized for that type.
Nothing prevents you from using std::enable_if to solve your specific problem, though that may be not the best way to do it.
If C++20 concepts were already largely adopted I'd say that that would be your way to go.
You could go the way as suggested here on SO and implement a class is_streamable which can check for that like this:
#include <type_traits>
#include <utility>
#include <iostream>
#include <sstream>
template<typename S, typename T>
class is_streamable
{
template<typename SS, typename TT>
static auto test(int)
-> decltype(std::declval<SS&>() << std::declval<TT>(), std::true_type());
template<typename, typename>
static auto test(...)->std::false_type;
public:
static const bool value = decltype(test<S, T>(0))::value;
};
class C
{
public:
friend std::stringstream& operator<<(std::stringstream &out, const C& c);
};
std::stringstream& operator<<(std::stringstream& out, const C& c)
{
return out;
}
int main() {
std::cout << is_streamable<std::stringstream, C>::value << std::endl;
return 0;
}
This would return one if the operator is implemented and zero if not.
With that you can alter your snippet to
template <typename T, typename = typename
std::enable_if<is_streamable<std::stringstream, C>::value, T>::type>
There are several thing you want:
a trait, is_streamable
a way to forbid class instantiation.
For the traits, you might use std::experimental_is_detected or run your own:
template <typename T>
auto is_streamable_impl(int)
-> decltype (T{},
void(), // Handle evil operator ,
std::declval<std::istringstream &>() >> std::declval<T&>(),
void(), // Handle evil operator ,
std::true_type{});
template <typename T>
std::false_type is_streamable_impl(...); // fallback, ... has less priority than int
template <typename T>
using is_streamable = decltype(is_streamable_impl<T>(0));
Then to forbid intantiation, several choices:
static_assert:
template <typename T>
class Input
{
static_assert(is_streamable<T>::value);
// ...
};
or SFINAE friendly class:
template <typename T, typename = std::enable_if_t<is_streamable<T>>>
class Input
{
// ...
};
so you allow to know if Input<T1> is valid.
Notice that without all that stuff, your program won't compile anyway when instantiating the problematic method (hard error, so no SFINAE friendly).
Being SFINAE friendly is not necessary most of the time.
If I have a complicated function that I want to use for two collections with matching interfaces (at least as far as the function in question is concerned) is there a way to just re-use the template code?
For example:
void DoSomethingIntense(std::vector<blah> myBlah);
void DoSomethingIntense(std::array<blah> myBlah);
If I use begin, end, size, and other functions that both array and vector have in common, is there a way to re-use the body of DoSomethingIntense without typing it twice (or, heaven forbid, stuffing it into a macro)?
(Please do not nitpick the example code, it doesn't help anybody)
UPDATE: My apologies, I neglected to mention that the function in question has other implementations for classes that do not match this signature; just making every argument use the code that works for these two is not an option.
I think the iterator solution might be best in that scenario.
Yes, use a template.
template <typename Container>
void DoSomethingIntense(Container blah) { // Might be better as Container const &
// write code using blah.begin() or whatever
}
You might be able to make it even more generic, following the example of STL, by supporting a general iterator range rather than specifically a container:
template <typename Iterator>
void DoSomethingIntense(Iterator begin, Iterator end);
Yes, you can achieve that by using templates:
template<typename T>
void DoSomethingIntense(const T &myBlah);
EDIT:
If I get your update right then I would say make use of SFINEA:
template<typename T>
struct is_vector : std::false_type {};
template<typename T, typename A>
struct is_vector<std::vector<T, A>> : std::true_type {};
template<typename T>
struct is_array : std::false_type {};
template<typename T, size_t N>
struct is_array<std::array<T, N>> : std::true_type {};
// add more if you want or define a macro
template<typename T>
std::enable_if_t<is_vector<T>::value || is_array<T>::value, void>
DoSomethingIntense(const T &myBlah)
{
}
int main()
{
std::vector<int> v;
DoSomethingIntense(v); // OK
std::array<float, 5> a;
DoSomethingIntense(a); // OK
std::queue<int> q;
DoSomethingIntense(q); // ERROR
}
You can mix templates / overloads. No problem.
For example:
template <typename T>
void DoSomethingIntense(T myBlah) {
}
void DoSomethingIntense(MyCustomClass myBlah) {
}
Then it will use the non-template version for argument type MyCustomClass and the template version for anything else (like vector or array)
Moreover, you can use std::enable_if to restrict the range of possible template arguments. See also this question.
in my work we do a lot of pair programming, and i wrote a function that ONLY accepts containers of a SINGLE type or its derivates, but my co-worker is afraid it will fail code review because it looks so damn ugly and says there's gotta be a better way:
here is the signature, the Fruit class is a base class that i renamed Fruit just for this thread:
template <class Container>
typename enable_if<is_base_of<Fruit, typename remove_pointer<typename Container::value_type>::type>::value, void>::type
processFruits(container& fruits)
{
//process the elements and change them if needed. thats why no const
}
what it does is: returns void and enables the function IF its a container AND the type inside the container is a Fruit and/or derivided of fruit. i also used std::remove_pointer because i needed to know the "type" of the pointer (the container will most likely have pointers).
this compiles and works as intended, but as i said i don't know it its the best way to do it, it seems too verbose and might get cut of on code review.
EDIT: this also accepts templated classes, don't have to be containers. is there a way i can limit it to only accept STL containers?
any alternate ideas or is it fine like it is?
thanks in advance.
It is a bit horrible to read.
Well for starters you don't need to say enable_if<B, void> you can just say enable_if<B> and use the default template argument.
You can easily split it into separate pieces:
template <class T>
struct is_fruity
: is_base_of<Fruit, T>
{ };
template <class Container, typename Value = typename Container::value_type>
struct is_fruit_container
: is_fruity<typename remove_pointer<Value>::type>>
{ };
template<class Container>
typename enable_if<is_fruit_container<Container>::value>::type
processFruits(Container& fruits)
{
//process the elements and change them if needed. thats why no const
}
If you have a compiler supporting alias templates you can make it even easier to read:
template<typename Cond>
using Require = typename enable_if<Cond::value>::type;
template<class Container>
Require<is_fruit_container<Container>>
processFruits(Container& fruits)
{
//process the elements and change them if needed. thats why no const
}
this also accepts templated classes, don't have to be containers. is there a way i can limit it to only accept STL containers?
I'm not sure what you mean by "templated classes", it only accepts types with a nested value_type type which is a type derived from Fruit or a pointer to such type, it doesn't have to be a template. To limit it to "STL containers" you need to write a trait to indentify an "STL container", however you want to define that. To do it properly you'd need a trait that tests for begin(), end(), size() members, as well as all the nested types specified by the container requirements, iterator, value_type, etc.
template<typename C, typename Chead, typename... Ctail>
struct static_and
{
static const bool value = C::value && static_and<Chead, Ctail...>::value;
};
template<typename C>
struct static_and<C>
{
static const bool value = C::value;
};
template<typename C>
struct is_container
: static_and<has_begin<C>, has_end<C>, has_iterator<C>, has_value_type<C> /* etc */>
{ };
I need a template like this, which work perfectly
template <typename container> void mySuperTempalte (const container myCont)
{
//do something here
}
then i want to specialize the above template for std::string so i came up with
template <typename container> void mySuperTempalte (const container<std::string> myCont)
{
//check type of container
//do something here
}
which doesnt't work, and throws an error. I would like to make the second example work and then IF possible i would like to add some code in the template to check if a std::vector/std::deque/std::list was used, to do something differently in each case.
So i used templates because 99% of the code is the same for both vectors and deques etc.
To specialize:
template<> void mySuperTempalte<std:string>(const std::string myCont)
{
//check type of container
//do something here
}
To specialize for vector:
template<typename C> void mySuperTempalte (std::vector<C> myCont)
{
//check type of container
//do something here
}
To specialize for deque:
template<typename C> void mySuperTempalte (std::deque<C> myCont)
{
//check type of container
//do something here
}
Have you tried a template typename parameter? The syntax is a bit weird because it emulates the syntax used to declare such a container. There's a good InformIT article explaining this in more detail.
template <template <typename> class Container>
void mySuperTemplate(Container<std::string> const& cont) {
}
Notice that you also should declare the argument as a reference!
By the way: this comment
//check type of container
is a dead giveaway that you're doing something wrong. You do not want to check the type of the container. User more sophisticated overloading instead, as shown in sep's answer.
If I am understanding your problem correctly you have an algorithm that will work for STL containers vector, deque etc but are trying to write a template specialisation for string. If this is the case then you can write the generalised templated method that you defined in your question:-
template<typename container> void mySuperTempalte( const container &myCont )
{
// Implement STL container code
}
Then for your string specialisation you declare:-
template<> void mySuperTempalte( const container<std::string> &myCont )
{
// Implement the string code
}
For any other specialisation just change the type declaration for myCont. If you really need to do this for the vector and deque containers then make the template parameter the parameter for the type in that container rather than the container itself as Sep suggested.
template<typename C> void mySuperTempalte( const std::vector<C> &myCont)
{
// check type of container
// do something here
}
It's worth trying to avoid this by making your first implementation work with all STL containers to make your life easier, then you only need the specialisation for the string class. Even consider converting your string to a vector to avoid the specialisation all together.
On a side note, I've changed the container parameter to a const reference, I assume this is what you want, as you declare the object const anyway, this way you avoid a copy.
The answers so far seem helpful, but I think I'd use a different construct. I expect all containers to define value_type, just like the STL containers do. Therefore, I can write
inline template <typename C> void mySuperTemplate (C const& myCont)
{
mySuperTemplateImpl<C, typename C::value_type>(myCont);
}
In general, it's easier to act on a parameter that you've extracted explicitly.
#sep
'Simple' solution
The answer posted by 'sep' is pretty good, probably good enough for 99% of app developers, but could use some improvement if it's part of a library interface, to repeat:
To specialize for vector:
template<typename C> void mySuperTempalte (std::vector<C> myCont)
{
//check type of container
//do something here
}
This will work provided the caller isn't using std::vector. If this works well enough for you, to specialize for vector, list, etc, then stop here and just use that.
More complete solution
First, note that you can't partially specialize function templates -- you can create overloads. And if two or more of them match to the same degree, you will get "ambigous overload" errors. So we need to make exactly one match in every case you want to support.
One technique for doing this is using the enable_if technique -- enable_if allows you to selectively take function template overloads out of the possible match list using an obscure language rule... basically, if some boolean expression is false, the overload becomes 'invisible'. Look up SFINAE for more info if you're curious.
Example. This code can be compiled from the command line with MinGW (g++ parameterize.cpp) or VC9 (cl /EHsc parameterize.cpp) without error:
#include <iostream>
#include <vector>
#include <string>
using namespace std;
template <bool B, class T> struct enable_if {};
template <class T> struct enable_if<true, T> { typedef T type; };
template <class T, class U> struct is_same { enum { value = false }; };
template <class T> struct is_same<T,T> { enum { value = true }; };
namespace detail{
// our special function, not for strings
// use ... to make it the least-prefered overload
template <class Container>
void SpecialFunction_(const Container& c, ...){
cout << "invoked SpecialFunction() default\n";
}
// our special function, first overload:
template <class Container>
// enable only if it is a container of mutable strings
typename enable_if<
is_same<typename Container::value_type, string>::value,
void
>::type
SpecialFunction_(const Container& c, void*){
cout << "invoked SpecialFunction() for strings\n";
}
}
// wrapper function
template <class Container>
void SpecialFunction(const Container& c){
detail::SpecialFunction_(c, 0);
}
int main(){
vector<int> vi;
cout << "calling with vector<int>\n";
SpecialFunction(vi);
vector<string> vs;
cout << "\ncalling with vector<string>\n";
SpecialFunction(vs);
}
Output:
d:\scratch>parameterize.exe calling
with vector<int> invoked
SpecialFunction() default
calling with vector<string> invoked
SpecialFunction() for strings
d:\scratch>
Whether it is a good design or not is left for further discussion. Anyway, you can detect the type of container using partial template specializations. In particular:
enum container_types
{
unknown,
list_container,
vector_container
};
template <typename T>
struct detect_container_
{
enum { type = unknown };
};
template <typename V>
struct detect_container_< std::vector<V> > // specialization
{
enum { type = vector_container };
};
template <typename V>
struct detect_container_< std::list<V> >
{
enum { type = list_container };
};
// Helper function to ease usage
template <typename T>
container_types detect_container( T const & )
{
return static_cast<container_types>( detect_container_<T>::type );
}
int main()
{
std::vector<int> v;
assert( detect_container( v ) == vector_container );
}