У меня есть пара типов, разделяющих свободные отношения клиент / сервер. Типы нетривиальны, поэтому, чтобы сделать их тестируемыми на модуле, я разделил их по аспектам с помощью декоратора. Каждый декоратор добавляет один аспект функциональности, такой как блокировка API с мьютексом, автоматическая регистрация c, повторение операций при сбое и тому подобное. Цепочка декоратора не изменяется во время выполнения, поэтому я пытался express использовать ее с помощью crtp и девиртуализированной поли-среды выполнения.
Я нашел случай, когда я думаю, что g cc должен быть в состоянии девиртуализировать, но это только частично. Если я помогу с обходным решением, он удастся девиртуализировать, определив методы пересылки непосредственно в типах листьев. Clang девиртуализируется без обходного пути.
Я что-то не так делаю, возможно, вызываю UB, или это g cc?
В приведенном ниже примере типы root не украшены, украшенные типы украшают корни, а типы листьев являются окончательными. Корни параметризуются на листьях для crtp, декораторы дополнительно параметризуют то, что они украшают, и листья непараметризованы, предназначенные для производства. Все API-интерфейсы здесь представлены в терминах типов листьев.
g cc девиртуализируется только тогда, когда определено ENABLE_WORKAROUND
.
ссылка Godbolt: https://godbolt.org/z/V85CoZ
#include <cstdint>
// #define ENABLE_WORKAROUND
template <typename leaf_client>
class root_server
{
public:
virtual auto associate(leaf_client& client) noexcept -> void { client_ = &client; }
virtual auto on_operation(leaf_client& client) noexcept -> std::intptr_t
{
return reinterpret_cast<std::intptr_t>(&client);
}
private:
leaf_client* client_{};
};
template <typename leaf_client, typename leaf_server, typename undecorated_server>
class decorated_server : public undecorated_server
{
public:
auto associate(leaf_client& client) noexcept -> void override
{
undecorated_server::associate(client);
client.on_associate(static_cast<leaf_server&>(*this));
}
auto on_operation(leaf_client& client) noexcept -> std::intptr_t override
{
return undecorated_server::on_operation(client);
}
};
template <typename leaf_client, typename leaf_server>
class root_client
{
public:
virtual auto on_associate(leaf_server& server) noexcept -> void { server_ = &server; }
virtual auto operation() -> std::intptr_t { return server_->on_operation(static_cast<leaf_client&>(*this)); }
private:
leaf_server* server_{};
};
template <typename leaf_client, typename leaf_server, typename undecorated_client>
class decorated_client : public undecorated_client
{
public:
auto on_associate(leaf_server& server) noexcept -> void override { undecorated_client::on_associate(server); }
auto operation() -> std::intptr_t override { return undecorated_client::operation(); }
};
class leaf_client;
class leaf_server;
using base_server = decorated_server<leaf_client, leaf_server, root_server<leaf_client>>;
class leaf_server final : public base_server
{
public:
#if defined ENABLE_WORKAROUND
auto on_operation(leaf_client& client) noexcept -> std::intptr_t override
{
return base_server::on_operation(client);
}
#endif
};
using base_client = decorated_client<leaf_client, leaf_server, root_client<leaf_client, leaf_server>>;
class leaf_client final : public base_client
{
public:
#if defined ENABLE_WORKAROUND
auto on_associate(leaf_server& server) noexcept -> void override { return base_client::on_associate(server); }
#endif
};
auto main() -> int
{
auto server = leaf_server{};
auto client = leaf_client{};
server.associate(client);
return client.operation();
}