C++20stladvanced
std::copy_constructible (C++20 Addition)
C++20 · The Big Four · Compiler flag: -std=c++20
Explanation
Concept that checks if a type can be copy-constructed from an lvalue. Refines `move_constructible` by also requiring copies from `const T&` and `T&` to work.
Real-World Scenario
Implement a snapshot system that clones the current state, requiring all components to be copyable.
Quick Snippet
snippet.cpp
#include <concepts>
template<std::copy_constructible State>
class Snapshotter {
std::vector<State> history;
public:
void snapshot(const State& current) {
history.push_back(current); // requires copy construction
}
};Full Example
copy_constructible.cpp
// CodeNebula - C++20 Example: std::copy_constructible Concept
// Compile: g++ -std=c++20 -Wall -Wextra -o example copy_constructible.cpp
// std::copy_constructible<T> is satisfied when T can be constructed from
// both lvalue and rvalue references, and from const references. This is
// stronger than move_constructible: all copy_constructible types are also
// move_constructible.
#include <concepts>
#include <iostream>
#include <memory>
#include <string>
#include <vector>
// A copyable value type
struct Color {
int r, g, b;
Color(int r, int g, int b) : r(r), g(g), b(b) {}
};
std::ostream& operator<<(std::ostream& os, const Color& c) {
return os << "(" << c.r << "," << c.g << "," << c.b << ")";
}
// Clone function: only works with copy_constructible types
template <std::copy_constructible T>
T clone(const T& original) {
return T(original); // explicit copy
}
// Broadcast: fill a vector with copies of a value
template <std::copy_constructible T>
std::vector<T> broadcast(const T& value, std::size_t count) {
return std::vector<T>(count, value);
}
template <typename T>
void check_copy(const char* name) {
std::cout << name << " - copy: " << std::copy_constructible<T>
<< ", move: " << std::move_constructible<T> << "\n";
}
int main() {
// Clone values
Color red(255, 0, 0);
auto red_copy = clone(red);
std::cout << "Original: " << red << "\n";
std::cout << "Clone: " << red_copy << "\n";
auto s = clone(std::string("hello"));
std::cout << "Cloned string: " << s << "\n";
// Broadcast
auto colors = broadcast(Color(0, 128, 255), 3);
std::cout << "\nBroadcast colors: ";
for (const auto& c : colors) std::cout << c << " ";
std::cout << "\n";
auto nums = broadcast(42, 4);
std::cout << "Broadcast ints: ";
for (int n : nums) std::cout << n << " ";
std::cout << "\n";
// Concept checks: copy vs move constructible
std::cout << "\nConstructibility checks:\n";
check_copy<int>("int");
check_copy<std::string>("string");
check_copy<Color>("Color");
check_copy<std::vector<int>>("vector<int>");
check_copy<std::unique_ptr<int>>("unique_ptr<int>");
return 0;
}
// Expected output:
// Original: (255,0,0)
// Clone: (255,0,0)
// Cloned string: hello
//
// Broadcast colors: (0,128,255) (0,128,255) (0,128,255)
// Broadcast ints: 42 42 42 42
//
// Constructibility checks:
// int - copy: 1, move: 1
// string - copy: 1, move: 1
// Color - copy: 1, move: 1
// vector<int> - copy: 1, move: 1
// unique_ptr<int> - copy: 0, move: 1
Run command
g++ -std=c++20 -Wall -Wextra -o example copy_constructible.cpp