如何创建类型特征以避免编写冗余的专用化?

How to create a type trait to avoid writing redundant specializations?

提问人:Unemployed Goose 提问时间:6/14/2023 最后编辑:JeJoUnemployed Goose 更新时间:6/15/2023 访问量:70

问:

我有一个带有主模板的类模板,该模板旨在与任何类型参数一起使用。但是,由于某些特殊需求,我需要像这样使用模板专用化:T

template<typename T>
class foo 
{
private:
    T result;
public:
    void modify_result(T a)
    {
        result = some_operations(a);
    }
};

template<>
class foo<uint64_t> 
{
private:
    uint64_t result;
public:
    // notice: uint32_t not the same as our template argument
    void modify_result(uint32_t a)
    {
        result = some_operations(a);
    }
};

问题在于,我必须为我的每个特定案例创建大量完整的专业化。如果我想修改或添加一些东西到类中,我将不得不为每个专业化做,这对可维护性来说真的很糟糕。

我想要某种类型特征来检查 .如果是某种类型,例如 ,那么我们知道方法的输入或方法中的某些变量需要是 类型。这将使我能够自定义我的模板,而无需额外的维护成本。TTuint64_tuint32_t

C++ 模板 template-specialization 类模板

评论


答:

4赞 songyuanyao 6/14/2023 #1

您可以定义类型特征,并为每个特定类型添加专用化,例如:

template <typename T>
struct parameter_type {
    using type = T;
};

template <>
struct parameter_type<uint64_t> {
    using type = uint32_t;
};

然后将其用作:

template<typename T>
class foo {
private:
    T result;
public:
    void modify_result(typename parameter_type<T>::type a) {
        result = some_operations(a);
    }
};

评论

3赞 Jan Schultke 6/14/2023
注意:为了避免到处写,您还可以在类中声明类型别名,或者从 C++20 开始。typename parameter_type<T>::typeusing parameter = typename parameter_type<T>::type;using parameter = parameter_type<T>::type;
2赞 JeJo 6/14/2023 #2

在 C++17 中,我会建议 if constexpr,检查您希望单独处理的每种类型。通过这样做,您将能够在一个地方看到不同类型的实现,从而(可以说)轻松维护代码。

template<typename T> class foo 
{
private:
   T result;
public:

   template<typename U>
   void modify_result(U a) 
   {
       if constexpr (std::is_same_v<U, uint64_t>)
       {
           // ... do something special for uint64_t type 'a'.
           result = some_operations(a);
       }
       else if constexpr (std::is_same_v<U, std::string>)
       {
           // ... do something special for std::string type 'a'.
           result = some_operations(a);
       }
       else
       {
           // ... all other types cases!
       }
   } 
};
1赞 463035818_is_not_an_ai 6/14/2023 #3

其他答案建议使用类型特征constexpr if。第三种选择是将所有依赖于模板参数的内容重构为基类,但仅此而已:

template<typename T>
class foo_base {
private:
    T result;
public:
    void modify_result(T a) {
        result = some_operations(a);
    }
};

template<>
class foo<uint64_t> {
private:
    uint64_t result;
public:
    void modify_result(uint32_t a) {
        result = some_operations(a);
    }
};

template <typename T>
class foo : public foo_base {
    // anything that does not depend on T is here
};

这样你只需要写一次,就可以专攻.在三种选择中,我会选择类型特征。constexpr 如果很好,当要专用的部分只是在有限的范围内并且继承并不总是正确的工具时(sloopy 说,当你实际上只想更改一个实现细节时,它会改变你的类型。虽然有时你想改变类型是什么......foofoo_base