Skip to content

Instantly share code, notes, and snippets.

@eao197
Created April 12, 2019 06:07
Show Gist options
  • Save eao197/eb73f67ba10ccb8322f42e9368c0b2a3 to your computer and use it in GitHub Desktop.
Save eao197/eb73f67ba10ccb8322f42e9368c0b2a3 to your computer and use it in GitHub Desktop.
CTRP and C++ template magic for compile-time control (more advanced version)
#include <iostream>
enum class msg_count_status_t
{
undefined,
defined
};
struct basic_data_t
{
int to_extract_{};
int to_handle_{};
int common_payload_{};
};
template<typename Basic_Data>
class basic_data_holder_t
{
private :
Basic_Data data_;
protected :
void set_to_extract(int v) { data_.to_extract_ = v; }
void set_to_handle(int v) { data_.to_handle_ = v; }
void set_common_payload(int v) { data_.common_payload_ = v; }
public :
basic_data_holder_t() = default;
basic_data_holder_t(Basic_Data data) : data_{std::move(data)} {}
int to_extract() const { return data_.to_extract_; }
int to_handle() const { return data_.to_handle_; }
int common_payload() const { return data_.common_payload_; }
const auto & data() const { return data_; }
auto & data() { return data_; }
};
template<typename Data, typename Derived>
class basic_params_t : public basic_data_holder_t<Data>
{
using base_type = basic_data_holder_t<Data>;
public :
using actual_type = Derived;
using data_type = Data;
protected :
actual_type & self_reference()
{ return static_cast<actual_type &>(*this); }
decltype(auto) clone_as_defined()
{
return actual_type::template clone_if_necessary<
msg_count_status_t::defined >( self_reference() );
}
public :
basic_params_t() = default;
basic_params_t(data_type data) : base_type{std::move(data)} {}
decltype(auto) handle_all()
{
this->set_to_handle(0);
return clone_as_defined();
}
decltype(auto) handle_n(int v)
{
this->set_to_handle(v);
return clone_as_defined();
}
decltype(auto) extract_n(int v)
{
this->set_to_extract(v);
return clone_as_defined();
}
actual_type & common_payload(int v)
{
this->set_common_payload(v);
return self_reference();
}
using base_type::common_payload;
};
template<
msg_count_status_t Msg_Count_Status,
template<msg_count_status_t> typename T>
struct cloner_t
{
template<msg_count_status_t New_Msg_Count_Status>
static std::enable_if_t<
New_Msg_Count_Status != Msg_Count_Status,
T<New_Msg_Count_Status> >
clone_if_necessary(const T<Msg_Count_Status> & self)
{
return { self.data() };
}
template<msg_count_status_t New_Msg_Count_Status>
static std::enable_if_t<
New_Msg_Count_Status == Msg_Count_Status,
T<Msg_Count_Status>& >
clone_if_necessary(T<Msg_Count_Status> & self)
{
return self;
}
};
struct receive_specific_data_t final : public basic_data_t
{
int receive_payload_{};
receive_specific_data_t() = default;
receive_specific_data_t(int v) : receive_payload_{v} {}
};
template< msg_count_status_t Msg_Count_Status >
class receive_specific_params_t final
: public basic_params_t<
receive_specific_data_t,
receive_specific_params_t<Msg_Count_Status> >
, public cloner_t<Msg_Count_Status, receive_specific_params_t>
{
using base_type = basic_params_t<
receive_specific_data_t,
receive_specific_params_t<Msg_Count_Status> >;
public :
receive_specific_params_t(int receive_payload)
: base_type{ typename base_type::data_type{receive_payload} }
{}
receive_specific_params_t(typename base_type::data_type data)
: base_type{ std::move(data) }
{}
int receive_payload() const { return this->data().receive_payload_; }
};
receive_specific_params_t<msg_count_status_t::undefined>
make_receive_params(int receive_payload)
{
return {receive_payload};
}
template<msg_count_status_t Msg_Count_Status>
void do_something(const receive_specific_params_t<Msg_Count_Status> & params)
{
static_assert(
Msg_Count_Status == msg_count_status_t::defined,
"message count to be processed/extracted should be defined "
"by using handle_all()/handle_n()/extract_n() methods" );
std::cout << "to_handle: " << params.to_handle() << std::endl;
std::cout << "to_extract: " << params.to_extract() << std::endl;
std::cout << "common_payload: " << params.common_payload() << std::endl;
std::cout << "receive_payload: " << params.receive_payload() << std::endl;
}
struct select_specific_data_t final : public basic_data_t
{
int select_payload_{};
select_specific_data_t() = default;
};
template< msg_count_status_t Msg_Count_Status >
class select_specific_params_t final
: public basic_params_t<
select_specific_data_t,
select_specific_params_t<Msg_Count_Status> >
, public cloner_t<Msg_Count_Status, select_specific_params_t>
{
using base_type = basic_params_t<
select_specific_data_t,
select_specific_params_t<Msg_Count_Status> >;
public :
select_specific_params_t() = default;
select_specific_params_t(typename base_type::data_type data)
: base_type{ std::move(data) }
{}
decltype(auto) select_payload(int v)
{
this->data().select_payload_ = v;
return *this;
}
int select_payload() const { return this->data().select_payload_; }
};
select_specific_params_t<msg_count_status_t::undefined>
make_select_params()
{
return {};
}
template<msg_count_status_t Msg_Count_Status>
void do_something(const select_specific_params_t<Msg_Count_Status> & params)
{
static_assert(
Msg_Count_Status == msg_count_status_t::defined,
"message count to be processed/extracted should be defined "
"by using handle_all()/handle_n()/extract_n() methods" );
std::cout << "to_handle: " << params.to_handle() << std::endl;
std::cout << "to_extract: " << params.to_extract() << std::endl;
std::cout << "common_payload: " << params.common_payload() << std::endl;
std::cout << "select_payload: " << params.select_payload() << std::endl;
}
int main()
{
std::cout << "*** receive ***" << std::endl;
do_something( make_receive_params(42).handle_all().common_payload(13) );
std::cout << "\n*** select ***" << std::endl;
do_something(
make_select_params()
.extract_n(20).common_payload(13)
.select_payload(55)
.handle_n(3) );
}
// vim:ts=3:sts=3:sw=3:expandtab
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment