Standard Library Containers with additional optional template parameters?
I found the following issue report, which says
There is no ambiguity; the standard is clear as written. Library implementors are not permitted to add template parameters to standard library classes. This does not fall under the "as if" rule, so it would be permitted only if the standard gave explicit license for implementors to do this. This would require a change in the standard.
The LWG decided against making this change, because it would break user code involving template template parameters or specializations of standard library class templates.
The books and people that say an implementation may add other optional parameters seem to be wrong.
template classes as template parameters
Why not just pass the container type as template parameter, and find out the element type from it? In your example code you don't even need the element type:
template <typename C>
ostream&
operator<<
(ostream& p_os,const C& p_c)
{
typedef typename C::value_type element_type; // if needed
for(typename C::const_iterator cit=p_c.begin();cit!=p_c.end();++cit)
{
p_os.operator<<(*cit);
}
return p_os;
}
(Although it might be unwise to use this for global functions like this without some enable_if
trickery, since it will otherwise match any argument.)
EDIT: You could for example attempt to restrict this to classes with a nested value_type
(which all containers have):
template <typename C, typename T = typename C::value_type>
ostream&
operator<<
(ostream& p_os,const C& p_c)
Pass a container type as the typename of a template in c++
With minimum changes to make it work, your code could be this:
#include <array>
template <typename T>
int find_size(const T& t)
{
return (t.size());
}
int main(void)
{
std::array<int, 10> test;
for (int i = 0; i < 10; i++)
{
test[i] = i;
}
find_size(test);
}
basically I want my function to be able to take an abritary type of container
Thats exactly what the above does. It works for any container type T
that has a size()
.
If you actually want to parametrize find_size
on a template rather than a type, then you can use a template template parameter:
#include <array>
template <template<class,std::size_t> class C>
int find_size(const C<int,10>& t)
{
return (t.size());
}
int main(void)
{
std::array<int, 10> test;
for (int i = 0; i < 10; i++)
{
test[i] = i;
}
find_size<std::array>(test);
}
However, using this is either more complicated than illustrated here, or of more limited use than the above: For the function parameter you need a type not just a template, and this find_size
will only work with a template C
that has 2 parameters, one type and one non-type parameter of type size_t
(and I am actually not aware of any other container but std::array
with that template parameters).
TL;DR: This is not a use case where a template template parameter is needed.
Is it possible to pass the template of a container to the template of a function?
Yes, but you don't need it here.
STL container as template parameter in function, error in call
std::vector
isn't a template of one parameter, it takes an allocator type as well. You can use it as vector<T>
simply because the second parameter has a default (std::allocator<T>
).
As it's written, your template function cannot accept any standard container, since off the top of my head, none take just a single type parameter.
An approach that would work, and not require you to know how many template parameters a container requires, is to accept a container type (not template), and glean the value type from the container type.
template<class Seq>
void show_sequence(Seq const& sequence)
{
typedef typename Seq::value_type T;
for_each(sequence.begin(), sequence.end(), show_element<T>);
}
All standard containers have a value_type
member, so this will work with any of them. Furthermore, it will work with any container that takes its cue from the standard library.
Why alias a template parameter in C++ standard containers?
I was wondering why the convention of assigning a type alias to a
template type is used here?
Because it is
- the standard way of doing,
- makes less error-prone code,
- less typing,
- more readable, and
- all the above makes life easy!
For instance, let's consider the const_pointer
, public template alias of std::vector
using const_pointer = typename _Alty_traits::const_pointer;
At some point, you want to know this type and use in a function, how could have been possible without the above alias?
Of course, you can write
#include <memory> // std::allocator_traits
using const_pointer = typename std::allocator_traits<typename std::vector</*type*/>::allocator_type>::const_pointer;
anywhere in your program. But that tends to more error-prone situations (e.g. missing some typename
s and so on), and more typing.
Therefore, it makes sense to collect those kinds of types of a container and provide public-aliases-types.
Optional Template parameter
You can have default template arguments, which are sufficient for your purposes:
template<class T, class U = T, class V = U>
class Test
{ };
Now the following work:
Test<int> a; // Test<int, int, int>
Test<double, float> b; // Test<double, float, float>
Default values in templates with template arguments ( C++ )
Perhaps you'd prefer this:
#include <vector>
#include <list>
using namespace std;
template <class Container>
class ForExamplePurposes {
typedef typename Container::value_type T;
Container items;
public:
};
int main()
{
ForExamplePurposes< list<int> > a;
ForExamplePurposes< vector<float> > b;
}
This uses "static duck typing". It is also a bit more flexible as it doesn't force the Container type to support STL's Allocator concept.
Perhaps using the type traits idiom can give you a way out:
#include <vector>
#include <list>
using namespace std;
struct MyFunkyContainer
{
typedef int funky_type;
// ... rest of custom container declaration
};
// General case assumes STL-compatible container
template <class Container>
struct ValueTypeOf
{
typedef typename Container::value_type type;
};
// Specialization for MyFunkyContainer
template <>
struct ValueTypeOf<MyFunkyContainer>
{
typedef MyFunkyContainer::funky_type type;
};
template <class Container>
class ForExamplePurposes {
typedef typename ValueTypeOf<Container>::type T;
Container items;
public:
};
int main()
{
ForExamplePurposes< list<int> > a;
ForExamplePurposes< vector<float> > b;
ForExamplePurposes< MyFunkyContainer > c;
}
Someone who wants to use ForExamplePurposes
with a non-STL-compliant container would need to specialize the ValueTypeOf
traits class.
C++ standard container and STL container in c++
Nothing in the C++ Standard Library "belongs" to the STL. STL is a different library that only influenced many parts in the C++ Standard Library. From the tag wiki:
[STL] is a C++ library of generic containers, iterators, algorithms,
and function objects. When C++ was standardised, large parts of the
STL were adopted into the Standard Library, […]
However, many people refer to the C++ Standard Library as the Standard Template Library, which is not entirely correct. I'm guessing that if you're not allowed to use the STL, they actually mean that you're not allowed to use the C++ Standard Library. But you'd have to ask them to know what they really mean.
For more information, see What's the difference between "STL" and "C++ Standard Library"?
Related Topics
Building a 32-Bit Float Out of Its 4 Composite Bytes
Emulating Shifts on 32 Bytes with Avx
Dll Redirection Using Manifests
Why Does Printf("%F",0); Give Undefined Behavior
Fast N Choose K Mod P for Large N
C++ Memory Model and Race Conditions on Char Arrays
Istream Behavior Change in C++ Upon Failure
How to Write to a Memory Buffer With a File*
How to Pass a Function Pointer That Points to Constructor
What Are the Issues with a Vector-Of-Vectors
Why Is This Cin Reading Jammed
Explain Morris Inorder Tree Traversal Without Using Stacks or Recursion
Workaround for Template Argument Deduction in Non-Deduced Context