Skip to content

86 Advanced The Hundred

The Type the Compiler Refused to Believe

spelled right, scoped right, and still not a type

#include <iostream>
#include <vector>

template <class C> void scale_front(C& c) {
    C::value_type* p = &c.front();   // point at the first element
    *p *= 10;
    std::cout << "front is now " << c.front() << "\n";
}

int main() {
    std::vector<int> v{7, 8, 9};
    scale_front(v);
}

Run it. What does it print?

Answer

Nothing — it doesn't compile, and GCC's first complaint isn't about the type at all: error: 'p' was not declared in this scope.

Why

When the compiler first parses a template it knows nothing about C, so it cannot look inside C:: to see what value_type is — and the standard tells it to assume that a qualified dependent name is a value. Under that reading the line is not a declaration at all: it parses as the assignment (C::value_type * p) = &c.front(), a product being assigned to, built out of a p that nobody declared — and it is that undeclared p the compiler complains about first. The value assumption is not paranoia: a specialization can make value_type a static constexpr int, and given a p already in scope the statement C::value_type* p; really does compile as a product, GCC shrugging only statement has no effect (-Wunused-value). typename is how you overrule the default, and once instantiation proves you meant a type, GCC all but writes the fix:

error: dependent-name 'C::value_type' is parsed as a non-type, but instantiation yields a type
note: say 'typename C::value_type' if a type is meant

Since C++20, typename is implied where only a type could possibly appear — a member declaration, a function's return type — but a function body is a context where declarations and expressions compete, so that whole category is excluded: inside one, typename stays mandatory in every standard.

The fix

typename C::value_type* p = &c.front();   // no, really, it's a type

Takeaway: inside a template, a dependent qualified name means a value unless you say typename.

Try it: g++ -std=c++17 main.cpp -o demo && ./demo — prints front is now 70 (the shipped main.cpp uses the fix); add -DSHOW_BUG to get the errors above.

Open in Compiler Explorer ↗ Open SHOW_BUG variant ↗ Quiz this entry