Simple C ++ templates suitable for STL containers

I need a template that works great

template <typename container> void mySuperTempalte (const container myCont) { //do something here } 

then I want to specialize this 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 does not work, and throws an error. I would like to do a second example of work, and then IF maybe, I would like to add code to the template to check if std :: vector / std :: deque / std :: list was used to do something different in each case, so I used patterns because 99% of the code is the same for both vectors, as well as for deques, etc.

+4
source share
6 answers

If I understand your problem correctly, you have an algorithm that will work for vector containers STL, deque, etc., but is trying to write a template specialization for a string. If so, you can write a generic template method that you defined in your question: -

 template<typename container> void mySuperTempalte( const container &myCont ) { // Implement STL container code } 

Then for your custom string, you declare: -

 template<> void mySuperTempalte( const container<std::string> &myCont ) { // Implement the string code } 

For any other specialization, 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 a parameter for the type in this container, and not the container itself, as September suggested.

 template<typename C> void mySuperTempalte( const std::vector<C> &myCont) { // check type of container // do something here } 

It is worth trying to avoid this by doing your first implementation job with all STL containers to make your life easier, then you only need specialization for the string class. Even consider converting your string to a vector to avoid specializing all together.

On the other hand, I changed the container parameter to a const link, I assume that this is what you want as you declare a const object anyway, so you avoid copying.

+5
source

Specialize:

 template<> void mySuperTempalte<std:string>(const std::string myCont) { //check type of container //do something here } 

Specializing for Vector:

 template<typename C> void mySuperTempalte (std::vector<C> myCont) { //check type of container //do something here } 

Specializing for deque:

 template<typename C> void mySuperTempalte (std::deque<C> myCont) { //check type of container //do something here } 
+7
source

Have you tried the typename template parameter? The syntax is a bit weird as it emulates the syntax used to declare such a container. There is a good InformIT article explaining this in more detail.

 template <template <typename> class Container> void mySuperTemplate(Container<std::string> const& cont) { } 

Note that you must also declare the argument as a reference!

By the way: this comment

 //check type of container 

- This is a dead sale, that you are doing something wrong. You do not want to check the type of container. Instead, the user will be more complex overload, as shown in the sep answer.

+7
source

The answers so far seem useful, but I think I would use a different construct. I expect all containers to define value_type, like STL containers. 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 explicitly extracted.

+4
source

@sep

"A simple solution

The answer posted by "sep" is pretty good, probably good enough for 99% of application developers, but might use some improvement if it is part of the library interface to repeat:

Specializing for Vector:

 template<typename C> void mySuperTempalte (std::vector<C> myCont) { //check type of container //do something here } 

This will work if the caller does not use std :: vector. If this works well enough for you to specialize in vector, list, etc., then stop here and just use it.

More complete solution

First, note that you cannot partially specialize function templates — you can create overloads. And if two or more of them coincide with the same degree, you will get "ambiguous overload" errors. Therefore, we need to make exactly one match in each case that you want to support.

One of the methods for this is to use the enable_if method - enable_if allows you to selectively intercept function templates from a list of possible matches using an obscure language rule ... basically, if some logical expression is false, the overload becomes "invisible". See SFINAE for more information if you are interested.

Example. This code can be compiled from the command line using MinGW (g ++ parameterize.cpp) or VC9 (cl / EHsc parameterize.cpp) without errors:

 #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> 
+3
source

Whether it will be a good design or not remains for further discussion. In any case, you can determine the type of container using private specialized templates. 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 ); } 
+1
source

Source: https://habr.com/ru/post/950512/


All Articles