C++17stladvanced
std::is_swappable / std::is_nothrow_swappable
C++17 · Practical Modern · Compiler flag: -std=c++17
Explanation
Type traits that check whether a type can be swapped with `std::swap` (`is_swappable`) and whether that swap is guaranteed not to throw (`is_nothrow_swappable`). These enable conditional noexcept specifications and better container optimizations.
Real-World Scenario
Write a generic container that provides a strong exception guarantee by checking whether its element type can be swapped without throwing.
Quick Snippet
snippet.cpp
#include <type_traits>
#include <string>
static_assert(std::is_swappable_v<int>);
static_assert(std::is_nothrow_swappable_v<int>);
static_assert(std::is_swappable_v<std::string>);
template<typename T>
void optimizedSwap(T& a, T& b) noexcept(std::is_nothrow_swappable_v<T>) {
std::swap(a, b);
}Full Example
is_swappable.cpp
// CodeNebula - C++17 Example: std::is_swappable / std::is_nothrow_swappable
// Compile: g++ -std=c++17 -Wall -Wextra -o example is_swappable.cpp
// Demonstrates the C++17 type traits for detecting whether types support
// swapping, and whether that swap is noexcept. Useful for writing generic
// code that needs to conditionally enable swap-based operations.
#include <iostream>
#include <type_traits>
#include <string>
#include <vector>
// A type that cannot be swapped (deleted swap)
struct NoSwap {
NoSwap() = default;
NoSwap(NoSwap&&) = delete;
NoSwap& operator=(NoSwap&&) = delete;
};
// A type with a noexcept swap
struct SafeSwap {
int data = 0;
friend void swap(SafeSwap& a, SafeSwap& b) noexcept {
std::swap(a.data, b.data);
}
};
// A type with a potentially-throwing swap
struct ThrowSwap {
int data = 0;
friend void swap(ThrowSwap& a, ThrowSwap& b) {
// Not marked noexcept
std::swap(a.data, b.data);
}
};
int main()
{
// ------------------------------------------------------------------
// 1. is_swappable: can a type be swapped?
// ------------------------------------------------------------------
std::cout << "=== std::is_swappable ===" << std::endl;
std::cout << " int : " << std::is_swappable_v<int> << std::endl;
std::cout << " std::string : " << std::is_swappable_v<std::string> << std::endl;
std::cout << " vector<int> : " << std::is_swappable_v<std::vector<int>> << std::endl;
std::cout << " SafeSwap : " << std::is_swappable_v<SafeSwap> << std::endl;
std::cout << " ThrowSwap : " << std::is_swappable_v<ThrowSwap> << std::endl;
std::cout << " NoSwap : " << std::is_swappable_v<NoSwap> << std::endl;
// ------------------------------------------------------------------
// 2. is_nothrow_swappable: can a type be swapped without throwing?
// ------------------------------------------------------------------
std::cout << "\n=== std::is_nothrow_swappable ===" << std::endl;
std::cout << " int : " << std::is_nothrow_swappable_v<int> << std::endl;
std::cout << " std::string : " << std::is_nothrow_swappable_v<std::string> << std::endl;
std::cout << " SafeSwap : " << std::is_nothrow_swappable_v<SafeSwap> << std::endl;
std::cout << " ThrowSwap : " << std::is_nothrow_swappable_v<ThrowSwap> << std::endl;
// ------------------------------------------------------------------
// 3. is_swappable_with: can two different types be swapped?
// ------------------------------------------------------------------
std::cout << "\n=== std::is_swappable_with ===" << std::endl;
std::cout << " int& <-> int& : "
<< std::is_swappable_with_v<int&, int&> << std::endl;
std::cout << " int& <-> double&: "
<< std::is_swappable_with_v<int&, double&> << std::endl;
// ------------------------------------------------------------------
// 4. Practical: constexpr-if conditional swap
// ------------------------------------------------------------------
auto safe_swap = [](auto& a, auto& b) {
if constexpr (std::is_nothrow_swappable_v<std::decay_t<decltype(a)>>) {
std::cout << " Swapping (noexcept path)" << std::endl;
using std::swap;
swap(a, b);
} else if constexpr (std::is_swappable_v<std::decay_t<decltype(a)>>) {
std::cout << " Swapping (may-throw path)" << std::endl;
using std::swap;
swap(a, b);
} else {
std::cout << " Cannot swap this type!" << std::endl;
}
};
std::cout << "\n=== Practical ===" << std::endl;
int x = 10, y = 20;
safe_swap(x, y);
std::cout << " x=" << x << " y=" << y << std::endl;
return 0;
}
/*
Expected output:
=== std::is_swappable ===
int : 1
std::string : 1
vector<int> : 1
SafeSwap : 1
ThrowSwap : 1
NoSwap : 0
=== std::is_nothrow_swappable ===
int : 1
std::string : 1
SafeSwap : 1
ThrowSwap : 0
=== std::is_swappable_with ===
int& <-> int& : 1
int& <-> double&: 0
=== Practical ===
Swapping (noexcept path)
x=20 y=10
*/
Run command
g++ -std=c++17 -Wall -Wextra -o example is_swappable.cpp