Plast interview

20. Template span

In a low-latency feed handler, generic code must compile to the same tight loops as hand-written versions. This snippet models a zero-copy view and a templated reduction used on hot paths.

template<class T> struct Span{ T* p; int n; };
template<class T> T sum(const Span<T>& s) noexcept { T r{}; for(int i=0;i<s.n;++i) r+=s.p[i]; return r; }
template<class T> T& head(Span<T>& s) noexcept { return s.p[0]; }
int main(){ int a[3]{1,2,3}; Span<int> s{a,3}; head(s)=4; auto x=sum(s); }

Part 1.

Which template instantiations are produced, and what is the final value of x? Justify briefly, noting value/reference behavior and copies.

Part 2.

(1) Add a const-correct head overload. When is it selected?

(2) Should sum be constexpr? When can evaluation be compile-time?

(3) Is noexcept correct for both? What optimizations rely on it?

(4) How to constrain sum to arithmetic T? SFINAE vs requires tradeoffs?

(5) Code bloat and inlining across many T: risks and mitigations?

Answer

Answer (Part 1)

Instantiated: Span<int>, head<int>, and sum<int>. head(s)=4 mutates a to {4,2,3}; sum<int> returns 9, stored in x. No extra copies of elements occur; head returns a reference, sum accumulates by value of T.

Answer (Part 2)

(1) Provide template<class T> const T& head(const Span<T>&) noexcept. It’s chosen when the Span<T> is const or a const T& is required.

(2) It can be constexpr, but this call won’t constant-fold. Requires all inputs be constant expressions and permissible pointer usage.

(3) noexcept is correct; indexing and addition cannot throw. It can enable better inlining, omit unwind paths, and improve code layout.

(4) Use a concept or trait constraint, e.g., requires std::is_arithmetic_v<T>. Concepts yield clearer errors; SFINAE is widely compatible but noisier.

(5) Many T instantiations inflate code size; instruction cache suffers. Mitigate via explicit instantiation, limiting supported T, and LTO-guided inlining.