If i have a type T
, what is a useful way to inspect it at compile time to see whether its an STL-style container (for an arbitrary value type) or not?
(Assumption: pointers, reference, etc. already stripped)
Starting code:
template<class T> // (1)
void f(T&) {}
template<class T> // (2)
void f(std::vector<T>&) {}
void test()
{
int a;
std::vector<int> b;
f(a);
f(b);
}
Now this works fine, but what if i want to generalize the container (i.e. not define (3), (4), ... explicitly)?
Utilizing SFINAE and typelists would reduce the code somewhat, but is there a better way?
Or is there an idiom for specializing based on concepts?
Or could i somehow utilize SFINAE to selectively enable only the desired specializations?
As a sidenote, i can't use iterators - i am trying to specialize based on functions that receive T
s as parameters.
As per MSalters answer:
template<class T>
void f(T&, ...) {
std::cout << "flat" << std::endl;
}
template<class Cont>
void f(Cont& c, typename Cont::iterator begin = Cont().begin(),
typename Cont::iterator end = Cont().end()) {
std::cout << "container" << std::endl;
}
(The variable argument list is needed to make the first f
the least preferred version to solve ambiguity errors)
STLcontainers by definition have a typedef iterator
, with 2 methods begin()
and end()
retruning them. This range is what the container contains. If there's no such range, it's not a container in the STL sense. So I'd sugegst something along the line of (not checked)
template<typename CONTAINER>
void f(CONTAINER& c,
typename CONTAINER::iterator begin = c.begin(),
typename CONTAINER::iterator end = c.end())
{ }
Anything you do is almost certain to be extremely fragile. There's simply no clean dividing line between what is or is not "STL". Even if there was a clean dividing line, it would almost certainly be a really poor basis for such a decision in any case. Just for example, if I write (or use) a re-implementation of std::map that's uses an AVL tree instead of the more common R-B tree, why should it be treated differently from std::map?
In the case of hashed containers, there's a whole progression from the various implementations of hash_map, to the Boost containers, to the TR1 containers, to those that will be included in the standard library in C++ 0x. Depending on how you define "STL", there's a pretty good chance that at least one of those isn't STL and another is, but there's no one point at which it's likely to make sense to treat one differently from another.
I think you should think about the characteristics of the containers, and then try to identify the characteristics that really matter to you.
According to www.cplusplus.com, the only functions that are common to all STL containers are:
- A constructor
operator=
size
.
At compile time, you can determine whether these operators exist on your type T
.
来源:https://stackoverflow.com/questions/1904796/specializing-functions-on-stl-style-container-types