Card 1 / 7
Container::value_type is a dependent name: what it refers to cannot be known until Container is. Since C++20 the compiler infers "type" wherever only a type could appear — a return type, a variable declaration — but inside a template argument list a value would also be legal, so there you still have to say which it is.
Container |
Container::value_type |
first_two(items) returns |
|---|---|---|
std::vector<int> |
int |
std::vector<int> |
std::vector<std::string> |
std::string |
std::vector<std::string> |
The keyword is typename, written immediately before the qualified name: std::vector<typename Container::value_type>. Without it GCC says exactly what it wants — "to refer to a type member of a template parameter, use typename Container::value_type".
// first_two returns a vector of the container's own element type. Container
// is a template parameter, so Container::value_type is a DEPENDENT name, and
// inside a template argument list the compiler cannot tell whether it names a
// type or a value.
//
// Add the one keyword that settles it.
template <class Container>
std::vector<
typename
Container::value_type>
first_two(const Container& items) {
return {items[0], items[1]};
}Card 2 / 7
device has a dependent type, so when the compiler reads device.read_as<double>() it has no idea that read_as is a template. It assumes the ordinary thing — a data member — and reads the < that follows as a less-than comparison,…