Okay, simple template question. Say I define my template class something like this:
template<typename T>
class foo {
public:
foo(T const& first, T const& second) : first(first), second(second) {}
template<typename C>
void bar(C& container, T const& baz) {
//...
}
private:
T first;
T second;
}
The question is about my bar function… I need it to be able to use a standard container of some sort, which is why I included the template/typename C part, to define that container type. But apparently that’s not the right way to do it, since my test class then complains that:
error: ‘bar’ was not declared in this scope
So how would I go about implementing my bar function the proper way? That is, as a function of my template class, with an arbitrary container type… the rest of my template class works fine (has other functions that don’t result in an error), it’s just that one function that’s problematic.
EDIT:
Okay, so the specific function (bar) is an eraseInRange function, that erases all elements in a specified range:
void eraseInRange(C& container, T const& firstElement, T const& secondElement) {...}
And an example of how it would be used would be:
eraseInRange(v, 7, 19);
where v is a vector in this case.
EDIT 2:
Silly me! I was supposed to declare the function outside of my class, not in it… pretty frustrating mistake to be making. Anyways, thanks everyone for the help, though the problem was a little different, the information did help me construct the function, since after finding my original problem, I did get some other pleasant errors. So thank you!
Traits solution.
Generalize not more than needed, and not less.
In some cases that solution might not be enough as it will match any template with such signature (e.g.
shared_ptr), in which case you could make use oftype_traits, very much like duck-typing (templates are duck typed in general).A good template usually does not artificially restrict the kind of types for which they are valid (why should they?). But imagine in the example above you need to have access to an objects
const_iterator, then you can use SFINAE and type_traits to put those constraints on your function.Or just to as the standard library does
Generalize not more than needed, and not less.
For more such examples, look into
<algorithm>.This approach’s strength is its simplicity and is based on concepts like ForwardIterator. It will even work for arrays. If you want to report errors right in the signature, you can combine it with traits.
stdcontainers with signature likestd::vector(not recommended)The simplest solution is approximated by Kerrek SB already, though it is invalid C++. The corrected variant goes like so:
However: this will only work for containers that have exactly two template type arguments, so will fail miserably for
std::map(thanks Luc Danton).Any kind of secondary template arguments (not recommended)
The corrected version for any secondary parameter count is as follows:
However: this will still fail for non-template containers (thanks Luc Danton).