In his keynote of this years Going Native The Essence of C++ (go to 40:30) Bjarne Stroustrup gives the following code example:
template<typename C, typename V>
vector<Value_type<C>*> find_all(C& cont, V v)
{
vector<Value_type<C>*> res;
for (auto& x : cont)
if (x == v)
res.push_back(&x)
return res;
}
This function is used to find all occurrences of a value in a container and returns pointers to the found elements. The example from the video:
string m{"Mary had a little lamb"};
for (const auto p: find_all(m,'a')) // p is a char*
if (*p != 'a')
cerr << "string bug!\n";
My question is about Value_Type<C>*
. Is there something like this in the standard
library? I looked for it and didn't find it. How could this be implemented, if it's not in std?
I don't know of this in the standard, but it's not hard to implement:
template <class C>
struct value_type
{
typedef typename C::value_type type;
};
template <class T, int N>
struct value_type<T[N]>
{
typedef T type;
};
template <class T>
struct value_type<T*>
{
typedef T type;
};
and now you can use typename value_type<C>::type
to access the type that a container contains. If you have your own container you would like to use but it doesn't have a value_type
typedef (and for whatever reason you can't change it) then you can simply specialize this struct for that container as well.
To avoid the typename ...::type
you can do:
template <class C>
using Value_Type = typedef value_type<C>::type;
and now you just use Value_Type<C>
everywhere.
EDIT
As stefan suggested in soon's answer, you can do this more easily with std::begin
which is okay because any container you use/create you would want to be able to call std::begin
and std::end
on anyway:
template <class C>
using Value_Type = typename std::remove_reference<
decltype(*std::begin(std::declval<
typename std::add_lvalue_reference<C>::type>()))>::type;
This is much more concise, though it's gotten a little dense to read. It's still better than the first option, this will require less boilerplate code for custom container types.
Value_type<C>
is just a typedef for C::value_type
. As far, as I know, there is no such typedef in standard library, but you could define it yourself:
template <class T>
using Value_type = typename T::value_type;
template<typename C, typename V>
std::vector<Value_type<C>*> find_all(C& cont, V v)
{
std::vector<Value_type<C>*> res;
for (auto& x : cont)
if (x == v)
res.push_back(&x);
return res;
}
int main()
{
std::vector<int> v{1, 2, 3, 3, 5};
for(const auto x: find_all(v, 3))
{
std::cout << *x << std::endl;
}
}
But, as suggested by @stefan, this will work with standard containers only. You could retrieve underlying type with using std::begin
function(which is defined for arrays too), how it's implemented in @GuyGreer's answer
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With