C++ - Reddit
229 subscribers
48 photos
8 videos
1 file
25.4K links
Stay up-to-date with everything C++!
Content directly fetched from the subreddit just for you.

Join our group for discussions : @programminginc

Powered by : @r_channels
Download Telegram
ICE with MSVC 17.11.4/Boost Spirit on invalid code - anyone able to reduce further?

using Boost 1.86 and MSVC 17.11.4/x64 Debug

there is a real bug/problem ((non class)enum and struct using same name) and the code does not compile with recent clang-cl/clang/gcc: https://gcc.godbolt.org/z/YxfTn7PY6

but Microsoft CL gets an internal compiler error (ICE) crash on this when the static qi::rule is active - can't see the relation - so the crash showing "other" problems inside the compiler :)

even when the example is broken the compiler should not crash - two runtime debugger dialogs pops up on compile

i want to reduce it further before filing an issue - can someone see the relation to the qt::rule?

main.cpp

#include <boost/spirit/include/qi.hpp>
#include <boost/fusion/adapted.hpp>

namespace qi = boost::spirit::qi;

enum Type{SameName};

struct SameName{};
BOOSTFUSIONADAPTSTRUCT( SameName )

#if 1
static qi::rule<std::string
view::constiterator, std::string()> somerule;
#endif

int main()
{
return 0;
}

CMakeLists.txt

cmakeminimumrequired(VERSION 3.28)
set (CMAKECXXSTANDARD 17)
project(ice)
addexecutable(icetests main.cpp)
# headers only - simplified (no package finding etc. needed for this ICE)
targetincludedirectories(icetests PUBLIC "../boost1860") # the zip-folder

how to install boost 1.86 (headers-only is enough - some seconds to build)

1. download:
https://archives.boost.io/release/1.86.0/source/
https://archives.boost.io/release/1.86.0/source/boost1860.7z
2. extract with 7zip
3. cd boost
1860
4. bootstrap.bat
5. b2 headers

https://redd.it/1fythpe
@r_cpp
error: no declaration matches 'int myclass::setnum(int)'

I genuinely don't understand where i've gone wrong with this incredibly basic experiment with classes. It returns an error for my set function but not my get function.


main.cpp


\
#include <iostream>

\
#include "myclass.h"



using namespace std;



int main()

{

myclass newobj;

cout << newobj.get\
num();

return 0;

}


myclass.h


\#ifndef MYCLASS_H

\#define MYCLASS_H





class myclass

{

private:

int num = 10;



public:

myclass();

int get_num();

void set_num(int x);

};



\#endif // MYCLASS_H

myclass.cpp

\#include "myclass.h"

\#include <iostream>



using namespace std;



myclass::myclass()

{

cout << "poo";

}



myclass::get_num()

{

return num;

}



myclass::set_num(int x)

{

num = x;

}


The error is on line 16 of myclass.cpp

https://redd.it/1gf7v11
@r_cpp
How is min and max not defined here?

\#ifndef min

\#define min( a, b ) ( (a) <= (b) ? (a) : (b) )

\#endif

\#ifndef max

\#define max( a, b ) ( (a) >= (b) ? (a) : (b) )

\#endif



\#ifndef clamp

\#define clamp( x, a, b ) min( max( (x), (a) ), (b) )

\#endif

https://redd.it/1h3lhw5
@r_cpp
Coroutines promise type

Hi there,

I've recently learnt about coroutines, and got excited as I maintain several async libraries, for which to support coroutines for at least the base library -the task scheduler-.

The task scheduler serves bare functions: No parameters , no return value, and I want to keep it as it is while supporting coroutine to coawait for periods, primarily.

Therefore I went to have the promise
type::getreturnobject() to return void, as no intention to enforce application/user to switch such tasks to different function signature, and to avoid double managing the tasks.

I've initially implemented that, with a compile error preventing me to proceed: error: unable to find the promise type for this coroutine.


Following is the main implementation of the coroutine, and here's the execution link: https://godbolt.org/z/4hWce9n6P

Am I getting coroutines wrong? What is suggested to do?

Thanks.

class H4Delay {
uint32_t duration;
task* owner;
task* resumer=nullptr;
public:
class promise_type {
task* owner=nullptr;
friend class H4Delay;
public:
void get_return_object() noexcept {}
std::suspend_never initial_suspend() noexcept { return {}; }
void return_void() noexcept {}
void unhandled_exception() noexcept { std::terminate(); }
struct final_awaiter {
bool await_ready() noexcept { return false; }
void await_suspend(std::coroutine_handle<promise_type> h) noexcept {
auto owner = h.promise().owner;
if (owner) owner->_destruct();
task::suspendedTasks.erase(owner);
// [ ] IF NOT IMMEDIATEREQUEUE: MANAGE REQUEUE AND CHAIN CALLS.

}
void await_resume() noexcept {}
};
final_awaiter final_suspend() noexcept { return {}; }

};
std::coroutine_handle<promise_type> _coro;

H4Delay(uint32_t duration, task* caller=H4::context) : duration(duration), owner(caller) {}
~H4Delay() {
if (_coro) _coro.destroy();
}

bool await_ready() noexcept { return false; }

void await_suspend(std::coroutine_handle<promise_type> h) noexcept {
// Schedule the resumer.
resumer = h4.once(duration, [h]{ h.resume(); });
_coro = h;
_coro.promise().owner = owner;
task::suspendedTasks[owner] = this;
}

void await_resume() noexcept { resumer = nullptr; }


void cancel() { ... }

};


https://redd.it/1h4akh4
@r_cpp
ImGui::NewFrame() throwing an error after second call

The error is: "abort() has been called"

This is the code:





#include <enet/enet.h>

#include <glad/glad.h>

#include <GLFW/glfw3.h>

#include <stb_image/stb_image.h>

#include <stb_truetype/stb_truetype.h>

#include "gl2d/gl2d.h"

#include <iostream>

#include <ctime>

#include "platformTools.h"

#include <raudio.h>

#include "platformInput.h"

#include "otherPlatformFunctions.h"

#include "gameLayer.h"

#include <fstream>

#include <chrono>

#include "errorReporting.h"

#include "imgui.h"

#include "backends/imgui_impl_glfw.h"

#include "backends/imgui_impl_opengl3.h"

#include "imguiThemes.h"





#ifdef _WIN32

#include <Windows.h>

#endif



#undef min

#undef max




int main()

{

GLFWwindow* window;







#pragma region window and opengl



permaAssertComment(glfwInit(), "err initializing glfw");

glfwWindowHint(GLFW_SAMPLES, 4);



#ifdef __APPLE__

glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, 1);

glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);

glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);

glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);

#endif





int w = 500;

int h = 500;

window = glfwCreateWindow(w, h, "Window", nullptr, nullptr);

glfwMakeContextCurrent(window);

glfwSwapInterval(1);





//permaAssertComment(gladLoadGL(), "err initializing glad");

permaAssertComment(gladLoadGLLoader((GLADloadproc)glfwGetProcAddress), "err initializing glad");







#pragma endregion



#pragma region gl2d

gl2d::init();

#pragma endregion





#pragma region imgui

ImGui::CreateContext();

imguiThemes::embraceTheDarkness();



ImGuiIO& io = ImGui::GetIO(); (void)io;

io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard;

`//io.ConfigFlags` |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls

io.ConfigFlags |= ImGuiConfigFlags_DockingEnable; // Enable Docking

io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable; // Enable Multi-Viewport / Platform Windows





ImGuiStyle& style = ImGui::GetStyle();

if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)

{

style.Colors[ImGuiCol_WindowBg].w = 0.f;

style.Colors[ImGuiCol_DockingEmptyBg].w = 0.f;

}



ImGui_ImplGlfw_InitForOpenGL(window, true);

ImGui_ImplOpenGL3_Init("#version 330");



#pragma endregion











while (!glfwWindowShouldClose(window))

{





glfwPollEvents();





ImGui_ImplOpenGL3_NewFrame();

ImGui_ImplGlfw_NewFrame();



glClearColor(0.0f, 0.0f, 0.0f, 1.0f);

glClear(GL_COLOR_BUFFER_BIT);





ImGui::NewFrame();

ImGui::Begin("My Scene");



ImGui::End();

ImGui::Render();





ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());



glfwSwapBuffers(window);







}







}

https://redd.it/1harvjb
@r_cpp
I don't understand how compilers handle lambda expressions in unevaluated contexts

Lambda expressions are more powerful than just being syntactic sugar for structs with operator(). You can use them in places that otherwise do not allow the declaration or definition of a new class.

For example:

template<typename T, typename F = decltype(
(auto a, auto b){ return a < b;} )>
auto compare(T a, T b, F comp = F{}) {
return comp(a,b);
}

is an absolutely terrible function, probably sabotage. Why?
Every template instantiation creates a different lamba, therefore a different type and a different function signature. This makes the lambda expression very different from the otherwise similar std::less.

I use static_assert to check this for templated types:

template<typename T, typename F = decltype((){} )>
struct Type {T value;};
template<typename T>
Type(T) -> Type<T>;
staticassert(not std::issamev<Type<int>,Type<int>>);

Now, why are these types the same, when I use the deduction guide?

static
assert(std::issamev<decltype(Type(1)),decltype(Type(1))>);

All three major compilers agree here and disagree with my intuition that the types should be just as different as in the first example.

I also found a way for clang to give a different result when I add template aliases to the mix:

template<typename T>
using C = Type<T>;

#if defined(clang)
staticassert(not std::issamev<C<int>,C<int>>);
#else
static
assert(std::issamev<C<int>,C<int>>);
#endif

So I'm pretty sure at least one compiler is wrong at least once, but I would like to know, whether they should all agree all the time that the types are different.

Compiler Explorer: https://godbolt.org/z/1fTa1vsTK

https://redd.it/1i3rpsm
@r_cpp
Can I put import inside the global module fragment?

So I am working on importizer that automatically create a module from a header file. It does so by collecting preprocessor directives, especially conditional ones, that has a #include inside and recreate it on top. For example:

// File.h
#pragma once
#ifdef COND
#include <vector>
#include <modularizedHeader.h>
#endif

will create this preamble

module;
#ifdef COND
#include <vector>
#endif
export module File;
#ifdef COND
import modularizedHeader;
#endif

which repeats the condition twice. With more complex conditions, the length will very quickly get out of hand.

Can I put import in the GMF like this to save some space?

module;
#ifdef COND
#include <vector>
import modularizedHeader;
#endif
export module File;

I was suspicious at first so I tested this approach on Godbolt (try putting the import into the GMF), and it's fine. I even read the C++ standard for modules, and I don't see any regulation about their location. Moreover, on cppreference, only preprocessing directives can go into the GMF, and import does count as one.

Is there any problem with doing it like this, and is there a better way to repeat the condition only once?

https://redd.it/1ihbb9f
@r_cpp
Zero-cost C++ wrapper pattern for a ref-counted C handle

Hello, fellow C++ enthusiasts!

I want to create a 0-cost C++ wrapper for a ref-counted C handle without UB, but it doesn't seem possible. Below is as far as I can get (thanks https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2020/p0593r6.html) :

// ---------------- C library ----------------
#ifdef __cplusplus
extern "C" {
#endif

struct ctrl_block { /* ref-count stuff */ };


struct soo {
char storageForCppWrapper; // Here what I paid at runtime (one byte + alignement) (let's label it #1)
/* real data lives here */
};

void useSoo(soo*);
void useConstSoo(const soo*);

struct shared_soo {
soo* data;
ctrl_block* block;
};

// returns {data, ref-count}
// data is allocated with malloc which create ton of implicit-lifetime type
shared_soo createSoo();


#ifdef __cplusplus
}
#endif



// -------------- C++ wrapper --------------
template<class T>
class SharedPtr {
public:
SharedPtr(T* d, ctrl_block* b) : data{ d }, block{ b } {}
T* operator->() { return data; }
// ref-count methods elided
private:
T* data;
ctrl_block* block;
};

// The size of alignement of Coo is 1, so it can be stored in storageForCppWrapper
class Coo {
public:
// This is the second issue, it exists and is public so that Coo has a trivial lifetime, but it shall never actually be used... (let's label it #2)
Coo() = default;

Coo(Coo&&) = delete;
Coo(const Coo&) = delete;
Coo& operator=(Coo&&) = delete;
Coo& operator=(const Coo&) = delete;

void use() { useSoo(get()); }
void use() const { useConstSoo(get()); }

static SharedPtr<Coo> create()
{
auto s = createSoo();
return { reinterpret_cast<Coo*>(s.data), s.block };
}

private:
soo* get() { return reinterpret_cast<soo*>(this); }
const soo* get() const { return reinterpret_cast<const soo*>(this); }
};

int main() {
auto coo = Coo::create();
coo->use(); // The syntaxic sugar I want for the user of my lib (let's label it #3)
return 0;
}

**Why not use the classic Pimpl?**

Because the ref-counting pushes the real data onto the heap while the Pimpl shell stays on the stack. A `SharedPtr<PimplSoo>` would then break the `SharedPtr` contract: should `get()` return the C++ wrapper (whose lifetime is now independent of the smart-pointer) or the raw C `soo` handle (which no longer matches the template parameter)? Either choice is wrong, so Pimpl just doesn’t fit here.

**Why not rely on “link-time aliasing”?**

The idea is to wrap the header in

# ifdef __cplusplus

\* C++ view of the type *\

# else

\* C view of the type *\

# endif

so the same symbol has two different definitions, one for C and one for C++. While this *usually* works, the Standard gives it no formal blessing (probably because it is ABI related). It blows past the One Definition Rule, disables meaningful type-checking, and rests entirely on unspecified layout-compatibility. In other words, it’s a stealth `cast` that works but carries no guarantees.

**Why not use** `std::start_lifetime_as` **?**

The call itself doesn’t read or write memory, but the Standard says that *starting* an object’s lifetime concurrently is undefined behaviour. In other words, it isn’t “zero-cost”: you must either guarantee single-threaded use or add synchronisation around the call. That extra coordination defeats the whole point of a free-standing, zero-overhead wrapper (unless I’ve missed something).

**Why this approach (I did not find an existing name for it so lets call it "reinterpret this")**

I am not sure, but this code seems fine from a standard point of view (even "#3"), isn't it ? Afaik, #3
+2913,7 @@ static void* vma_aligned_alloc(size_t alignment, size_t size)
#include <AvailabilityMacros.h>
#endif

-static void* vma_aligned_alloc(size_t alignment, size_t size)
+inline void* vma_aligned_alloc(size_t alignment, size_t size)
{
// Unfortunately, aligned_alloc causes VMA to crash due to it returning null pointers. (At least under 11.4)

Also, GCC 15 still doesn't support private module fragment, so I enclosed `module :private;` line with `#ifndef __GNUC__ ... #endif`.

And I retried...

FAILED: CMakeFiles/vku.dir/interface/mod.cppm.o CMakeFiles/vku.dir/vku.gcm
/home/gk/gcc-15/bin/g++ -isystem /home/gk/Downloads/vku/build/vcpkg_installed/arm64-linux/include -isystem /home/gk/Downloads/vku/build/vcpkg_installed/arm64-linux/share/unofficial-vulkan-memory-allocator-hpp/../../include -std=gnu++23 -MD -MT CMakeFiles/vku.dir/interface/mod.cppm.o -MF CMakeFiles/vku.dir/interface/mod.cppm.o.d -fmodules-ts -fmodule-mapper=CMakeFiles/vku.dir/interface/mod.cppm.o.modmap -MD -fdeps-format=p1689r5 -x c++ -o CMakeFiles/vku.dir/interface/mod.cppm.o -c /home/gk/Downloads/vku/interface/mod.cppm
In module imported at /home/gk/Downloads/vku/interface/debugging.cppm:11:1,
of module vku:debugging, imported at /home/gk/Downloads/vku/interface/mod.cppm:7:
vku:details.to_string: error: interface partition is not exported
In module imported at /home/gk/Downloads/vku/interface/descriptors/PoolSizes.cppm:12:1,
of module vku:descriptors.PoolSizes, imported at /home/gk/Downloads/vku/interface/descriptors/mod.cppm:9,
of module vku:descriptors, imported at /home/gk/Downloads/vku/interface/mod.cppm:8:
vku:details.concepts: error: interface partition is not exported
In module imported at /home/gk/Downloads/vku/interface/descriptors/DescriptorSetLayout.cppm:16:1,
of module vku:descriptors.DescriptorSetLayout, imported at /home/gk/Downloads/vku/interface/descriptors/mod.cppm:7,
of module vku:descriptors, imported at /home/gk/Downloads/vku/interface/mod.cppm:8:
vku:details.functional: error: interface partition is not exported
In module imported at /home/gk/Downloads/vku/interface/commands.cppm:14:1,
of module vku:commands, imported at /home/gk/Downloads/vku/interface/mod.cppm:10:
vku:details.container.OnDemandCounterStorage: error: interface partition is not exported
In module imported at /home/gk/Downloads/vku/interface/commands.cppm:15:1,
of module vku:commands, imported at /home/gk/Downloads/vku/interface/mod.cppm:10:
vku:details.tuple: error: interface partition is not exported
In module imported at /home/gk/Downloads/vku/interface/rendering/AttachmentGroup.cppm:15:1,
of module vku:rendering.AttachmentGroup, imported at /home/gk/Downloads/vku/interface/rendering/mod.cppm:8,
of module vku:rendering, imported at /home/gk/Downloads/vku/interface/mod.cppm:14:
vku:rendering.AttachmentGroupBase: error: interface partition is not exported
/home/gk/Downloads/vku/interface/mod.cppm:4: confused by earlier errors, bailing out
ninja: build stopped: subcommand failed.

I wrote the `detail::` namespace code into the separate module partitions, and they were only imported to the module partitions and not exported. But GCC requires them to be exported if an exported module partition is importing them.

diff --git a/interface/mod.cppm b/interface/mod.cppm
index 1148398..695d987 100644
--- a/interface/mod.cppm
+++ b/interface/mod.cppm
@@ -13,3 +13,13 @@ export import :pipelines;
export import :queue;
export import :rendering;
export import :utils;
+
+#ifdef __GNUC__
+// GCC requires all interface partitions to be exported.
+export import :details.to_string;
+export import :details.concepts;
+export import :details.functional;
+export import :details.container.OnDemandCounterStorage;
+export import :details.tuple;
+export import :rendering.AttachmentGroupBase;
+#endif

So I exported them... and retried again...

gk@fedora:~/Downloads/vku$ cmake
Can I put module declarations in header files?

Issue: https://github.com/Cvelth/vkfw/issues/19

So a while ago, I added module support to the vkfw library. It works fine for my usage with Clang, but recently (not really, it's been a while) GCC 15 released with module support finally stabilized. However, the way that module support is implemented is that in the header file vkfw.hpp, there is something like:

// ...
#ifdef VKFWMODULEIMPLEMENTATION
export module vkfw;
#endif
// ...

so that the vkfw.cpp file can be just:

module;
#define VKFWMODULEIMPLEMENTATION
#include <vkfw/vkfw.hpp>

However, GCC 15+ rejects compilation with

In file included from .../vkfw-src/include/vkfw/vkfw.cppm:3:
.../vkfw-src/include/vkfw/vkfw.hpp:219:8:
error: module control-line cannot be in included file

However, I can't find anywhere in the spec/cppreference that disallow this. So is this allowed at all, or it's just a GCC limitation?

https://redd.it/1lw2g0d
@r_cpp
T::ComponentType*, Error> temp = getComponentForEntity<typename T::ComponentType>(entity);
if (temp.has_value())
T{}(*temp.value());
}


template<std::derived_from<Component> T>
std::unordered_map<Entity, T>& ECS::getComponentMap()
{
static std::unordered_map<Entity, T> instance{};
return instance;
}
}


#endif

https://redd.it/1nyjayx
@r_cpp
state!");
}
} else {
destroy();
_tag = other._tag;
switch (_tag) {
case Tag::Ok: new (&_value.ok) T(other._value.ok); break;
case Tag::Err: new (&_value.error) E(other._value.error); break;
default:
panic("[_tag] was left in an invalid state!");
}
}

return *this;
}

Result &operator=(Result &&other) noexcept {
if (this == &other) {
return *this;
}

if (_tag == other._tag) {
switch (_tag) {
case Tag::Ok: _value.ok = move(other._value.ok); break;
case Tag::Err: _value.error = move(other._value.error); break;
default:
panic("[_tag] was left in an invalid state!");
}
} else {
destroy();
_tag = other._tag;
switch (_tag) {
case Tag::Ok: new (&_value.ok) T(move(other._value.ok)); break;
case Tag::Err: new (&_value.error) E(move(other._value.error)); break;
default:
panic("[_tag] was left in an invalid state!");
}
}

return *this;
}

private:
enum class Tag {
Ok,
Err
} _tag;

union Variant {
T ok;
E error;

constexpr Variant() noexcept {}
~Variant() noexcept {}
} _value;

explicit Result(Tag tag, const T &ok, OkOverload)
: _tag{ tag } {
new (&_value.ok) T(ok);
}

explicit Result(Tag tag, const E &error, ErrOverload)
: _tag{ tag } {
new (&_value.error) E(error);
}

explicit Result(Tag tag, T &&ok, OkOverload)
: _tag{ tag } {
new (&_value.ok) T(move(ok));
}

explicit Result(Tag tag, E &&error, ErrOverload)
: _tag{ tag } {
new (&_value.error) E(move(error));
}

void destroy() noexcept {
switch (_tag) {
case Tag::Ok: _value.ok.~T(); break;
case Tag::Err: _value.error.~E(); break;
default:
panic("[_tag] was left in an invalid state!");
}
}
};

struct Unit {};

template<typename T>
using Option = Result<T, Unit>;

template<typename E>
using Fallible = Result<Unit, E>;

#endif

```

https://redd.it/1okpb9k
@r_cpp
26)
```cpp
constexpr auto parse() {
// Allowed
static_assert(false, "Expected ';'");

// Not allowed :( (until C++ 26)
std::size_t line = 5;
static_assert(false, "Expected ';' at line " + to_string(line));
}
```
I didn't want my project to require C++ 26, so I used another trick. The formatted string gets turned into a static array just like a vector (into `const_string` actually) and then it's passed into `ErrorMessage<const_string Msg>` that triggers compilation error. So we force the compiler to print the full type name that includes our error. But sadly the type name has a limit about 100 symbols. I think I could solve it with splitting the message into several ErrorMessages... God, I don't want to read this in my console.
```c++
template<const_string Msg>
struct ErrorMessage {
static_assert(false, "Check the template parameter for details");
};

template<auto err_getter>
consteval auto report_error() -> void {
// C++ 26 support
#ifdef KORKA_FEATURE_FORMATTED_STATIC_ASSERT
static_assert(false, to_string(err_getter()));
#else
constexpr auto msg = const_string_from_string_view<[] { return to_string(err_getter()); }>();
std::ignore = ErrorMessage<msg>{};
#endif
}
```

I don't want you to see it, so I'll just show C++ 26 version.
```
error: static assertion failed: Lexer Error: Unterminated string at line 12
```

### Mapping signatures to names. And vice versa
In our little runtime C++ we are used to `std::unordered_map<string, value_t>` and other standard or non-standard (hello, Boost!) containers. But I needed a table where a key is a string and the value is a TYPE. And in C++ I can't treat types as values, I can't just put them into a dict... :(

So, welcome another hack!
```c++
template<auto, class>
struct signature_mapper;

// function_info_getter takes an index to our mapped function,
// and Is... holds all indices
template<auto function_info_getter, std::size_t... Is>
struct signature_mapper<
function_info_getter,
std::index_sequence<Is...>
> {
// hash func
consteval static auto hash(auto &&v) -> std::size_t {
return frozen::elsa<std::string_view>{}(v, 0);
}

// Our function overloaded with many unique types based on hash of the mapped function
constexpr static auto _overloaded = overloaded{
(
[](unique_type<hash(function_info_getter(Is).name)>)
-> const_function_info_to_signature_t<[] { return function_info_getter(Is); }> * {
return nullptr;
}
)...
};

// Extracting the type by name
template<const_string name>
using get_signature_t = std::remove_pointer_t<decltype(
_overloaded(
unique_type<hash(name)>{}
)
)>;

};
```

We use well-known function overload (~~but for evil things~~). Basically, one type inherits a lot of lambdas that take an empty `unique_type<hash>` that serves as our key and returns the pointer to our type.
```cpp
// How our mapper looks after expanding our params
struct overloaded : lambda1, lambda2, lambda3 {
using lambda1::operator();
using lambda2::operator();
using lambda3::operator();
};

// And every lambda looks like this
auto lambda_fib = [](unique_type<hash("fib")>) -> signature_of_fib* { return nullptr; };
```
When we call `_overloaded(unique_type<hash(name)>())` our poor compiler has to resolve the overload. And he looks for right one through all `()` operators. And then we just take that it returns (our `T*`) and get the `T`.
I use this "mechanism" to extract script functions into the native C++.
```cpp
constexpr auto script_fib = compile_result.function<"fib">();
```

### Bindings from C++ to our script lang
This was the most exhausting part. Well, how "exhausting" exactly... I was thinking for a few evenings and then made it work one morning. The problem was with me. I wanted to make a pretty API that was impossible in the current standard (maybe it's possible in C++ 26, but I didn't check it).
I wanted it to look like this:
```cpp
auto func() -> void;
auto foo(int) -> int;

// Примерно так
constexpr auto bindings = korka::make_bindings<
"func", func,
"foo", foo
>();

// Или так
constexpr auto