C++17stladvanced
std::as_const
C++17 · Practical Modern · Compiler flag: -std=c++17
Explanation
Returns a `const` reference to its argument, useful for forcing const overload selection without writing a verbose `static_cast<const T&>`. This is particularly handy when passing objects to templates that should not modify them.
Real-World Scenario
Pass a container to a function template ensuring the const overload of `begin()`/`end()` is selected for thread-safe iteration.
Quick Snippet
snippet.cpp
#include <utility>
#include <vector>
std::vector<int> data = {1, 2, 3};
// Forces use of const overloads
for (auto& val : std::as_const(data)) {
// val is const int& -- cannot be modified
std::cout << val << " ";
}Full Example
as_const.cpp
// CodeNebula - C++17 Example: std::as_const
// Compile: g++ -std=c++17 -Wall -Wextra -o example as_const.cpp
// Demonstrates std::as_const, a utility that adds a const qualifier to an
// lvalue reference. Useful for forcing const overload selection without
// writing a verbose const_cast or separate const reference variable.
#include <iostream>
#include <utility>
#include <string>
#include <vector>
#include <set>
// A class with const and non-const overloads
class Container {
std::vector<int> data_ = {10, 20, 30};
public:
// Non-const: returns mutable reference
std::vector<int>& items() {
std::cout << " [non-const overload]" << std::endl;
return data_;
}
// Const: returns const reference
const std::vector<int>& items() const {
std::cout << " [const overload]" << std::endl;
return data_;
}
};
// Template that behaves differently based on const-ness
template <typename T>
void inspect(T& val) { std::cout << " non-const ref" << std::endl; }
template <typename T>
void inspect(const T& val) { std::cout << " const ref" << std::endl; (void)val; }
int main()
{
// ------------------------------------------------------------------
// 1. Forcing const overload selection
// ------------------------------------------------------------------
Container c;
std::cout << "=== Overload Selection ===" << std::endl;
std::cout << " c.items():" << std::endl;
c.items(); // Calls non-const
std::cout << " std::as_const(c).items():" << std::endl;
std::as_const(c).items(); // Calls const
// ------------------------------------------------------------------
// 2. Range-based for without accidental mutation
// ------------------------------------------------------------------
std::vector<std::string> names = {"Alice", "Bob", "Charlie"};
std::cout << "\n=== Safe Iteration ===" << std::endl;
// Without as_const, auto& could accidentally allow mutation
for (const auto& name : std::as_const(names)) {
std::cout << " " << name << std::endl;
}
// ------------------------------------------------------------------
// 3. Template overload resolution
// ------------------------------------------------------------------
int x = 42;
std::cout << "\n=== Template Overload ===" << std::endl;
std::cout << " inspect(x): ";
inspect(x);
std::cout << " inspect(std::as_const(x)):";
inspect(std::as_const(x));
// ------------------------------------------------------------------
// 4. Preventing set element mutation through iterator
// ------------------------------------------------------------------
std::set<int> s = {1, 2, 3, 4, 5};
std::cout << "\n=== Const Set Iteration ===" << std::endl;
std::cout << " Elements: ";
for (auto it = std::as_const(s).begin(); it != std::as_const(s).end(); ++it) {
std::cout << *it << " ";
}
std::cout << std::endl;
// ------------------------------------------------------------------
// 5. Type verification
// ------------------------------------------------------------------
std::cout << "\n=== Type Properties ===" << std::endl;
std::cout << " x is const? : "
<< std::is_const_v<std::remove_reference_t<decltype(x)>> << std::endl;
std::cout << " as_const(x) is const? : "
<< std::is_const_v<std::remove_reference_t<decltype(std::as_const(x))>>
<< std::endl;
return 0;
}
/*
Expected output:
=== Overload Selection ===
c.items():
[non-const overload]
std::as_const(c).items():
[const overload]
=== Safe Iteration ===
Alice
Bob
Charlie
=== Template Overload ===
inspect(x): non-const ref
inspect(std::as_const(x)): const ref
=== Const Set Iteration ===
Elements: 1 2 3 4 5
=== Type Properties ===
x is const? : 0
as_const(x) is const? : 1
*/
Run command
g++ -std=c++17 -Wall -Wextra -o example as_const.cpp