子类中部分特化父方法

问题描述 投票:0回答:1

我有一个模板类,我想专门针对许多不同类型。比如:

#include <type_traits>
#include <string>
#include <string_view>

// To allow static assert for invalid branches
template <typename T>
inline constexpr bool invalid = false;

template <typename T>
struct TypeMeta
{
    using type = T;
    using intermediate_type = T;
    static consteval auto marshal_string() {static_assert(invalid<T>, "Not implemented for type.");}
    static constexpr auto convert(intermediate_type &&value) {return type{value};}
    static constexpr bool needs_conversion = !std::is_same_v<type, intermediate_type>;
};

我希望能够像这样覆盖此类的部分内容:

struct TypeMeta<std::string>
{
    using intermediate_type = const char *;
    static consteval std::string_view marshal_string() {return "s";}
};

然后进一步将其用于以下用途:

template <typename T>
T extract_from(void *data)
{
    using meta_t = TypeMeta<T>;
    if constexpr (meta_t::needs_conversion) {
        typename meta_t::intermediate_type tmp;
        tmp = *(static_cast<meta_t::intermediate_type *>(data));
        return meta_t::convert(tmp);
    } else {
        return *(static_cast<meta_t::type *>(data));
    }
}

显然,这对

std::string
不起作用,因为我还没有在我的专业领域中重新定义
type
needs_conversion
convert

现在,我可以通过使用 CRTP 继承一个基类来轻松解决这个问题。比如:

template <typename T>
struct TypeMeta;

template <typename T>
struct TypeMetaBase
{
    using type = T;
    using intermediate_type = T;
    static consteval auto marshal_string() {static_assert(invalid<T>, "Not implemented for type.");}
    static constexpr type convert(intermediate_type &&value) {return type{value};}
    static constexpr bool needs_conversion = !std::is_same_v<typename TypeMeta<T>::type, typename TypeMeta<T>::intermediate_type>;
};

template <typename T>
struct TypeMeta : public TypeMetaBase<T>{};

template <>
struct TypeMeta<std::string> : public TypeMetaBase<std::string>
{
    using intermediate_type = const char *;
    static consteval std::string_view marshal_string() {return "s";}
};

效果很好。我认为你必须记住从每种类型的基类继承,这有点不好,但这可能是不可避免的。 然而,当您只想专门化父级实际需要的一两个函数时,就会出现“真正的”问题。我想做这个:

template <> consteval std::string_view TypeMeta<int>::marshal_string() {return "i"}; 但是这是不允许的:

<source>:xx:yy: error: no member function 'marshal_string' declared in 'TypeMeta<int>'
   xx | consteval auto TypeMeta<int>::marshal_string() {return "i";}

我可以通过在模板中复制该方法来解决这个问题:

template <typename T>
struct TypeMeta : public TypeMetaBase<T>
{
        static consteval auto marshal_string() {static_assert(invalid<T>, "Not implemented for type.");}
};

这意味着像

std::string
 这样的专门结构体如果没有定义,将会回退到使用 
TypeMetaBase

的方法,而只有一些专门方法的结构体,比如

int
结构体将使用
TypeMeta
的方法对于那些不专业的人。
但这意味着我必须不必要地重复代码。我不喜欢那样。它很容易失去同步,并且启动时会出现不必要的膨胀。
有什么方法可以避免重复方法,同时允许最少的额外输入?我想我可以要求任何专业化声明自己的结构,但有许多不同的类型,其中大多数只需要一个重写的方法,我宁愿保持它尽可能简洁。

一个额外的想法可能是使用宏进行额外的结构声明以避免样板,但如果可能的话,我宁愿避免使用宏。

我基本上只是想获得一个不错的 C++ 解决方案,它不涉及滥用预处理器或复制粘贴代码。

您可以将每个组件拆分为自己的 type_traits:

c++ templates types c++20 crtp
1个回答
0
投票

然后只提供个人特征的专业化:

template <>
struct intermediate_type<std::string>
{
    using type = const char *;
};

template <>
consteval std::string_view marshal_string<std::string>() { return "s"; }

template <>
consteval std::string_view marshal_string<int>() { return "i"; }

演示

    

© www.soinside.com 2019 - 2024. All rights reserved.