I have a Bluetooth library that defines a link_layer
as the lowest protocol layer, that implements the link layer protocol on top of a radio
. The link_layer
itself is a template to allow the use of different radio
implementations. A radio
itself is a template too, to allow for different, basic configurations (eg buffer sizes).
A lot of radio implementation can share some common behavior, like buffers
. So some of the radio implementations combine a lot of implementation by inheriting from them (CRTP).
Now I need some details in the buffer
implementation that depend on the actual radio
implementation ( mapping
between in memory and over the air PDU layout). The obvious solution, to define that mapping
as a type in the radio does not work, because the radio inherits the buffer
implementation and at the point of the buffer
template instantiation, the radio
is thus still an incomplete type.
Recommended solution to this problem is to define that mapping as a type trait
and specialize the trait
for all radio
implementations. This worked very well, because there is a reasonable default, that works for a lot of radio
s.
Beside the buffer
, there is a different implementation detail (encryption) that I mix into the radio
implementation via inheritance. In one of the cases, where I need to specialize the trait
from above, that type itself is again a template. I mix in different encryption supporting types useing a factory
, that defines the radio
template as result. Here is a short sketch of the scenario:
#include <type_traits>
template < typename OtherOption, template < typename > class Radio >
struct link_layer : Radio< OtherOption >
{
};
template < class ConfiguredRadio >
struct trait
{
using mapping = int;
};
template < typename ConfiguredRadio >
struct buffers
{
using mapping = typename trait< ConfiguredRadio >::mapping;
};
template < typename Base >
struct radio_factory
{
template < typename T >
struct radio : buffers< radio< T > >, Base
{
};
};
struct radio_without_enryption_base {};
template < typename Option >
struct radio_with_enryption_base {};
template < typename Option, typename T >
struct trait<
typename radio_factory<
radio_with_enryption_base< Option >
>::template radio< T >
>
{
using mapping = short;
};
template < typename OtherOption >
using ll_without_encryption = link_layer<
OtherOption,
radio_factory< radio_without_enryption_base >::template radio >;
template < typename OtherOption >
using ll_with_encryption = link_layer<
OtherOption,
radio_factory< radio_with_enryption_base< OtherOption > >::template radio >;
int main()
{
static_assert( std::is_same< ll_without_encryption< int >::mapping, int >::value, "" );
static_assert( std::is_same< ll_with_encryption< int >::mapping, short >::value, "" );
}
All compilers I've tried complain, that the partial specialization of trait<>
contains template parameters that are not deducible. Is it possible to specialize a template with a template type, that is the inner type of another template? If not, what could a possible workaround look like?
typename someClass<T>::type
is not deducible.
workaround is to define the class not as inner type:
namespace detail
{
template<typename T, typename Base>
struct radio : buffers<radio<T, Base>>, Base
{
};
}
template < typename Base >
struct radio_factory
{
template <typename T>
using radio = details::radio<T, Base>; // Same interface as before
};
template <typename T, typename Option>
struct trait<detail::radio<T, radio_with_enryption_base<Option>>>
{
using mapping = short;
};
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.