#include <iostream>
class Wrap
{
public:
Wrap(int x) : value(x) {}
private:
int value;
template <class T>
friend void out(const T&);
};
template <>
void out(const Wrap& x)
{ std::cout << x.value << std::endl; }
int main()
{
Wrap x(42);
out(x);
return 0;
}
#include <iostream>
namespace qq {
template <class T>
void out(const T&);
}
class Wrap
{
public:
Wrap(int x) : value(x) {}
private:
int value;
template <class T>
friend void qq::out(const T&);
};
template <>
void qq::out(const Wrap& x)
{ std::cout << x.value << std::endl; }
int main()
{
Wrap x(42);
qq::out(x);
return 0;
}
char* text = "foo";
, а разработка Си(++) застопорилась на десятилетие, учебники по Си очень долго писали такую нерекомендуемую строчку.#include <iostream>
class WrapInt
{
public:
int value = 0;
WrapInt(int x) : value(x) {}
WrapInt(WrapInt&) = delete;
private:
};
int main()
{
WrapInt x = 42;
}
int zero = 0;
до C++14 — создать временный объект, вызвать конструктор перемещения, а остальное делает оптимизатор. С Си++17 — вызов конструктора, если он не explicit. Мне казалось, что в очень старых версиях DJGPP был задействован op=, но ХЕЗ, MinGW и Си++03 вызывают именно конструктор.int zero = int(0);
— что удивительно, то же самое, только конструктор любой! Хотя выглядит как явное создание временного объекта.int zero(0);
— вызов конструктора во всех версиях Си++.int zero{0};
— универсальный инициализатор Си++11, также вызов конструктора.int array[] = { 1, 2, 3};
— все версии Си и Си++. int array[] { 1, 2, 3};
— универсальный инициализатор Си++11.array[b] = newElem; ++b;
. Керниган и Ритчи решили объединить это чудо в одну строку array[b++] = newElem;
, к тому же в процессорах действительно бывают пред- и постинкрементные операции.std::string helloWorld(std::move(hello().operator std::string()));
typedef enum Buttons{
SAVE,
OPEN,
SORT,
EXIT
}Buttons;
#include <iostream>
#include <array>
#include <string>
enum class FromRawMem { INST };
enum class NoValue { INST };
#define consteval constexpr
class Char4
{
public:
using CppArray = std::array<char, 4>;
constexpr explicit Char4(NoValue) : fBuf { { 0, 0, 0, 0 } } {}
consteval Char4(const char (&x)[5]) : fBuf { { x[0], x[1], x[2], x[3] } } {}
constexpr Char4(const Char4&) = default;
Char4(FromRawMem, const char* data) { fBuf.asInt = *reinterpret_cast<const uint32_t*>(data); }
constexpr const CppArray& toAr() const { return fBuf.asAr; }
CppArray& toAr () { return fBuf.asAr; }
constexpr std::string_view toSv() const { return { fBuf.asAr.data(), 4 }; }
/// @return byte-order dependent integer value
/// @warning
/// DO NOT save toRawInt() as Intel, Motorola or any numeral system (decimal etc).
/// You MAY save it as raw memory, or use it for optimization.
constexpr uint32_t toRawInt() const { return fBuf.asInt; }
constexpr const char* data() const { return fBuf.asAr.data(); }
private:
union {
std::array<char, 4> asAr;
uint32_t asInt;
} fBuf;
};
constexpr inline bool operator == (Char4 x, Char4 y) { return x.toRawInt() == y.toRawInt(); }
constexpr inline bool operator != (Char4 x, Char4 y) { return x.toRawInt() != y.toRawInt(); }
constexpr inline bool operator == (Char4 x, std::string_view y)
{ return y.size() == 4 && x.toRawInt() == *reinterpret_cast<const uint32_t*>(y.data()); }
constexpr inline bool operator != (Char4 x, std::string_view y)
{ return !operator == (x, y); }
constexpr inline bool operator == (std::string_view x, Char4 y)
{ return operator == (y, x); }
constexpr inline bool operator != (std::string_view x, Char4 y)
{ return !operator == (y, x); }
/// Size of enum class, no generic implementation.
template <class Ec>
constexpr size_t enumSize();
namespace detail {
/// Jut does not compile if arguments contain assignments
constexpr int enumDummy(...) { return 0; }
template <typename T, std::size_t...Is>
consteval std::array<T, sizeof...(Is)>
make_array(const T& value, std::index_sequence<Is...>)
{
return {{(static_cast<void>(Is), value)...}};
}
template <std::size_t N, typename T>
consteval std::array<T, N> make_array(const T& value)
{
return make_array(value, std::make_index_sequence<N>());
}
}
#define DEFINE_ENUM_SIZE(Name) \
template <> constexpr size_t enumSize<Name>() { return static_cast<int>(Name::NN); }
#define DEFINE_ENUM_N(Name, ...) \
enum class Name { __VA_ARGS__ }; \
template <> constexpr size_t enumSize<Name>() { \
enum Internal { __VA_ARGS__ , NNNNNN }; \
detail::enumDummy(__VA_ARGS__); \
return NNNNNN; }
enum class DummyElem { INST };
enum class IncompleteArray { INST };
enum class FillArray { INST };
enum class PairwiseTempInit {INST };
namespace detail {
namespace array {
template <auto K, class V>
class KeyValue {
public:
static constexpr auto index = K;
V && v;
consteval KeyValue(V && aV) : v(aV) {}
};
// checkOneForRepeat
template <class Ec>
consteval void checkOneForRepeat() {}
template <class Ec, Ec Only>
consteval void checkOneForRepeat() {}
template <class Ec, Ec First, Ec Second, Ec ... Rest>
consteval void checkOneForRepeat()
{
static_assert(First != Second, "Repeating array keys!");
checkOneForRepeat<Ec, First, Rest...>();
}
// checkForRepeat
template <class Ec>
consteval void checkForRepeat() {}
template <class Ec, Ec Only>
consteval void checkForRepeat() {}
template <class Ec, Ec First, Ec Second, Ec ... Rest>
consteval void checkForRepeat()
{
checkOneForRepeat<Ec, First, Second, Rest...>();
checkForRepeat<Ec, Second, Rest...>();
}
template <class Ec, Ec ... args>
consteval void checkKeys()
{
checkForRepeat<Ec, args...>();
}
}
}
template<auto K, class V>
consteval auto kv(V && v) { return detail::array::KeyValue<K, V>(v); }
template <class T, class Ec>
class EcArray
{
public:
static constexpr auto Size = enumSize<Ec>();
using CppArray = std::array<T, Size>;
using Elem = T;
using iterator = Elem*;
using const_iterator = const Elem*;
constexpr CppArray& toAr() { return fBuf; }
constexpr const CppArray& toAr() const { return fBuf; }
constexpr Elem* data() { return fBuf.data(); }
constexpr const Elem* data() const { return fBuf.data(); }
constexpr size_t size() const { return Size; }
constexpr iterator begin() { return fBuf.begin(); }
constexpr iterator end() { return fBuf.end(); }
constexpr const_iterator begin() const { return fBuf.begin(); }
constexpr const_iterator end() const { return fBuf.end(); }
constexpr const_iterator cbegin() const { return fBuf.begin(); }
constexpr const_iterator cend() const { return fBuf.end(); }
constexpr EcArray() = delete;
constexpr EcArray(NoValue) {}
constexpr EcArray(const EcArray&) = default;
constexpr EcArray(EcArray&&) = default;
EcArray& operator = (const EcArray&) = default;
EcArray& operator = (EcArray&&) = default;
template <class U>
constexpr EcArray(NoValue, const U&& x) : fBuf {x } {}
template <class ... Args>
consteval EcArray(Args&& ... x)
: fBuf { x... }
{ static_assert(sizeof...(Args) == Size, "EcArray size mismatch"); }
template <class U, Ec K, class V, class ... Args>
consteval EcArray(
PairwiseTempInit, U&& temp,
detail::array::KeyValue<K, V> first,
Args&& ... rest)
: fBuf { detail::make_array<Size, T>(temp) }
{
static_assert(sizeof...(Args) + 1 == Size, "EcArray pairwise size mismatch");
detail::array::checkKeys< Ec, K, (std::remove_reference_t<decltype(rest)>::index)... >();
initPairwise(first, rest...);
}
private:
CppArray fBuf;
consteval void initPairwise() {}
template <Ec K, class V, class ... Args>
consteval void initPairwise(
detail::array::KeyValue<K, V> first,
Args&& ... rest)
{
fBuf[static_cast<size_t>(K)] = T { first.v };
initPairwise(rest...);
}
};
DEFINE_ENUM_N( Letter, A, B, C )
extern const EcArray <Char4, Letter> names2;
//const EcArray <Char4, Letter> names { "alph", "brav", "char" };
constinit const EcArray <Char4, Letter> names2
{ PairwiseTempInit::INST, Char4 { NoValue::INST},
kv <Letter::A> ( "alp1" ),
kv <Letter::B> ( "bra1" ),
kv <Letter::C> ( "cha1" ) };
int main()
{
std::cout << "Hello World!" << std::endl;
return 0;
}