3

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 Ts 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)

Community
  • 1
  • 1
Georg Fritzsche
  • 97,545
  • 26
  • 194
  • 236
  • Could you give an example of one specialization you want to make? – GManNickG Dec 15 '09 at 02:35
  • I tried, hope that gets the idea across. – Georg Fritzsche Dec 15 '09 at 02:46
  • Almost :P Could you rename `f` to match what the function does? – GManNickG Dec 15 '09 at 02:59
  • So you want the second to not just convert `x`, but to convert and insert all of the elements of `x`? – GManNickG Dec 15 '09 at 03:04
  • Now, wouldn't SFINAE normally kick in anyway? If `t` can't be `back_inserted` or `x` has no `at`, the first will be used. – GManNickG Dec 15 '09 at 03:14
  • That would give (or gives) me multiple definition errors, as far as i understand it, SFINAE only applies to the declaration. Updated a bit more context, but its slowly getting too big i think. – Georg Fritzsche Dec 15 '09 at 03:20
  • Oops, yea, don't know what I was thinking. – GManNickG Dec 15 '09 at 03:29
  • Well, it seems i have a talent for asking too open ended questions. – Georg Fritzsche Dec 15 '09 at 04:17
  • That does not work with gcc 4.3.3. The call to f(b) is ambiguous ! Do I have missed something ? – neuro Jan 11 '11 at 19:54
  • @neuro: I don't have time to dig it out right now, but i have implemented utilities for this in FireBreath [here](https://github.com/firebreath/FireBreath/tree/master/src/ScriptingCore/Util). There are e.g. [helpers for enabling functions for containers](https://github.com/firebreath/FireBreath/blob/master/src/ScriptingCore/Util/meta_util.h#L96) that are in `meta_util.h` and `meta_util_impl.h`, used e.g. with `boost::enable_if`. The framework is tested & used on multiple GCC versions and VS8-VS10. – Georg Fritzsche Jan 12 '11 at 14:28
  • @Georg: well thank you for the link. I will have a look. – neuro Jan 24 '11 at 16:02

3 Answers3

2

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.

Jerry Coffin
  • 476,176
  • 80
  • 629
  • 1,111
  • I wasn't trying to isolate stl containers, hence "stl style", but i am lost how to specialize based on the *characteristics*. – Georg Fritzsche Dec 15 '09 at 03:12
  • @gf:Why are you specializing on "stl style"? What divides "stl style" from "not stl style"? – Jerry Coffin Dec 15 '09 at 03:19
  • I meant supporting stl style operations. The idea was (may be overkill) to not only specialize on some containers and allow anly container that supports e.g. stl-style back insertion. – Georg Fritzsche Dec 15 '09 at 03:23
2

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())
{ }
MSalters
  • 173,980
  • 10
  • 155
  • 350
0

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.

Chip Uni
  • 7,454
  • 1
  • 22
  • 29