Reference:
For this reason, you can now use strings or vectors at compile time.
However, you cannot use the compile-time created strings or vectors at runtime because memory allocated at compile time has to be released at compile time.
#include <vector>
#include <ranges>
#include <algorithm>
#include <numeric>
template<std::ranges::input_range T>
constexpr auto modifiedAvg(const T& rg) {
using elemType = std::ranges::range_value_t<T>;
// initialize compile-time vector with passed elements:
std::vector<elemType> v{std::ranges::begin(rg),
std::ranges::end(rg)};
// perform several modifications:
v.push_back(elemType{});
std::ranges::sort(v);
auto newEnd = std::unique(v.begin(), v.end());
// return average of modified vector:
auto sum = std::accumulate(v.begin(), newEnd, elemType{});
return sum / static_cast<double>(v.size());
}
// 注意,要用constexpr不然modifiedAvg為runtime.
constexpr auto avg = modifiedAvg(orig);
// use concept
// initialize compile-time vector with passed elements
template<std::ranges::input_range T>
consteval auto modifiedAvg(T rg) {
using elemType = std::ranges::range_value_t<T>;
std::vector<elemType> v{std::ranges::begin(rg), std::ranges::end(rg)};
}
However, note that we still cannot declare and initialize a vector at compile time that is usable at runtime:
int main() {
constexpr std::vector orig{0, 8, 15, 132, 4, 77}; // ERROR
}
#include <vector>
constexpr auto returnVector() {
std::vector<int> v{0, 8, 15};
v.push_back(42);
return v;
}
constexpr auto returnVectorSize() {
constexpr auto coll = returnVector();
return coll.size();
}
int main() {
// constexpr auto coll = returnVector(); // ERROR
constexpr auto tmp = returnVectorSize();
}
#include <vector>
#include <ranges>
#include <algorithm>
#include <array>
template<std::ranges::input_range T>
consteval auto mergeValuesSz(T rg, auto... vals) {
// create compile-time vector:
std::vector<std::ranges::range_value_t<T>> v{
std::ranges::begin(rg), std::ranges::end(rg)};
(... , v.push_back(vals)); // and merge passed values
std::ranges::sort(v);
constexpr auto maxSz = rg.size() + sizeof...(vals);
std::array<std::ranges::range_value_t<T>, maxSz> arr{};
auto res = std::ranges::unique_copy(v, arr.begin());
return std::pair{arr, res.out - arr.begin()};
}
Rule of thumb: cannot use a compile-time string at runtime.
String SSO implement also take into account. (https://godbolt.org/z/eTYfcfMc5)
constexpr Language Extensions
Since C++20, the following language features are possible to be used in compile time functions (whether declared with constexpr or consteval):
- You can now use heap memory at compile time.
- Runtime polymorphism is supported:
- You can now use virtual functions.
- You can now use dynamic_cast.
- You can now use typeid.
- You can have try-catch blocks now (but you are still not allowed to throw).
- You can now change the active member of a union.
- Note that you are still not allowed to use static in constexpr or consteval functions.
lamdba
template<typename... Args>
void foo(Args... args) {
// OK since C++20
auto l4 = [...args = std::move(args)] {
bar(args...); // OK
};
}
template<typename... Args>
void foo(Args... args) {
auto l4 = [&...fooArgs = args] {
bar(fooArgs...); // OK
};
}
new type:
char8_t
std::u8string
std::u8string_view
char8_t c = u8'@'; // character with UTF-8 encoding for character @
const char8_t* s = u8"K\u00F6ln"; // character sequence with UTF-8 encoding for Köln
Synchronized Output Streams:
https://en.cppreference.com/w/cpp/io/basic_osyncstream
#include <iostream>
#include <cmath>
#include <thread>
#include <syncstream>
void squareRoots(int num) {
for (int i = 0; i < num ; ++i) {
std::osyncstream coutSync{std::cout};
coutSync << "squareroot of " << i << " is "
<< std::sqrt(i) << '\n';
}
}
int main() {
std::jthread t1(squareRoots, 5);
std::jthread t2(squareRoots, 5);
std::jthread t3(squareRoots, 5);
}
For writing to file:
#include <fstream>
#include <cmath>
#include <thread>
#include <syncstream>
void squareRoots(std::ostream& strm, int num) {
std::osyncstream syncStrm{strm};
for (int i = 0; i < num ; ++i) {
syncStrm << "squareroot of " << i << " is "
<< std::sqrt(i) << '\n' << std::flush_emit;
}
}
int main() {
std::ofstream fs{"tmp.out"};
std::jthread t1(squareRoots, std::ref(fs), 5);
std::jthread t2(squareRoots, std::ref(fs), 5);
std::jthread t3(squareRoots, std::ref(fs), 5);
}
or:
#include <fstream>
#include <cmath>
#include <thread>
#include <syncstream>
void squareRoots(std::ostream& strm, int num) {
for (int i = 0; i < num ; ++i) {
strm << "squareroot of " << i << " is "
<< std::sqrt(i) << '\n' << std::flush_emit;
}
}
int main() {
std::ofstream fs{"tmp.out"};
std::osyncstream syncStrm1{fs};
std::jthread t1(squareRoots, std::ref(syncStrm1), 5);
std::osyncstream syncStrm2{fs};
std::jthread t2(squareRoots, std::ref(syncStrm2), 5);
std::osyncstream syncStrm3{fs};
std::jthread t3(squareRoots, std::ref(syncStrm3), 5);
}
No comments:
Post a Comment
Note: Only a member of this blog may post a comment.