【问题标题】:Reducing duplication of template parameters in C++减少 C++ 中模板参数的重复
【发布时间】:2021-09-22 13:20:09
【问题描述】:

这不是主要的代码破坏问题,我只是想知道我是否错过了一些巧妙的技巧。

如果我正在编写一个模板类,我可能会这样开始:

// some_header.h
template <typename TypeParameter, size_t max_array_size>
class TemplatedClass
{
    std::array<TypeParameter, max_array_size> MyTemplatedArray;

public:
    TypeParameter do_something()
    {
        /* do something with TypeParameter and max_array_sizein here */
    }
}

这很好,但是当我有不那么琐碎的模板化示例时,我倾向于将函数定义与声明分开,如下所示:

// some_header.h
template <typename TypeParameter, size_t max_array_size>
class TemplatedClass
{
    std::array<TypeParameter, max_array_size> MyTemplatedArray;

public:
    TypeParameter do_something();

    /*

    Many more function declarations

    */
}

template <typename TypeParameter, size_t max_array_size>
TemplatedClass<TypeParameter, max_array_size>::do_something()
{
    /* do something with TypeParameter and max_array_sizein here */
}

/*

Many more function definitions, all with:

template <typename TypeParameter, size_t max_array_size>
TemplatedClass<TypeParameter, max_array_size>

at the start

*/

这样做的目的是拥有一个经典的骨架类定义,其他人一眼就能轻松阅读。我不介意这样做,但令人讨厌的是当我想修改模板参数时。第一个示例中的一个变化是什么,最终成为第二个示例中的1 + 2 * n 变化!

所以我想知道的是:有没有办法让第二个示例的模板参数更易于维护?可能是类似于 typedef/using 的东西,或者是我没听说过的关键字?

【问题讨论】:

  • 只要去掉声明和实现的分离。请注意,由于 C++ 继承了 C 的标头,因此需要此拆分,因此必须将代码放在 ccp 文件中并在头文件中声明。使用模板,一切都在头文件中(通常),没有必要分开。此外,C++20 终于引入了模块,这些模块将不再需要头文件,因此不再需要单独的声明和定义。
  • 如果/*do soemthing*/ 不依赖于模板参数,您应该将这些方法移至非模板基类。如果/*do something*/ 确实依赖于模板参数,那么无论如何您需要进行 2 次以上的更改。我认为您的问题没有很好的答案,但实际上这不是问题(也因为当重要时您仍然可以直接在类中定义方法)
  • 感谢@MarekR。我知道我可以坚持使用示例 1,但我认为示例 2 是一种相当普遍的做法,可以使事情更具可读性。也许并没有我想象的那么普遍。
  • 我只是说引入这种做法是为了解决一些无法解决的问题。现在它已经深深印在我们的脑海中(我的也是),有时在不需要时很难摆脱。
  • 你可以使用预处理器定义...

标签: c++ templates c++17


【解决方案1】:

首先是一个不回答:

假设,/*do something*/ 依赖于模板参数。在这种情况下,必须修复签名是较小的问题。您需要修复实现。

另一种情况是/*do something*/不依赖于模板参数。然后您可以将方法移动到非模板基类。


更认真地尝试回答这个问题:

如果TemplatedClass 只有一个模板参数而不是多个模板参数会怎样?您可以使用单个标签而不是为TemplatedClass 使用一堆模板参数,并且可以将实际参数的定义推迟到特征:

#include <array>

template <typename Tag> struct value_type_impl;
template <typename Tag> using value_type = typename value_type_impl<Tag>::type;
template <typename Tag> constexpr int array_size = 123;

template <typename Tag>
class TemplatedClass {
    std::array<value_type<Tag>, array_size<Tag> > MyTemplatedArray;    
public:
    value_type<Tag> do_something();
};

template <typename Tag>
value_type<Tag> TemplatedClass<Tag>::do_something() {
    return {};
}

// the tag
struct foo_tag{};

// specializations for foo_tag:
template <> struct value_type_impl<foo_tag> { using type = int; };
template <> constexpr int array_size<foo_tag> = 123;


int main() {
    TemplatedClass<foo_tag> tc;
}

现在的负担是模板的用户定义一个标签,然后为该标签专门化所需的特征。虽然,方法定义只有一个模板参数,当添加或删除更多“参数”(特征)时不需要更改。当然,您仍然需要修复实现。

如果您只是在寻找一些语法糖,我不知道在不更改模板本身的情况下会有什么帮助。

【讨论】:

  • 感谢您的回答!这似乎是一个解决方案,即使它不是我所希望的“巧妙的把戏”。我会给它一两天,然后如果没有其他问题,很可能会将其标记为解决方案!
  • @Cascades tbh 我认为这个答案的第一部分或 Mareks 评论(“只是不要这样做”)是正确的答案,我只是觉得这对于答案来说有点太苗条了,因此我试图找到符合您要求的方法:方便地定义与类分开的方法,避免在更改参数时更改参数。
  • 是的,我明白了!我不会使用您编写的代码,而只会按原样处理!非常感谢!
猜你喜欢
  • 2020-06-02
  • 1970-01-01
  • 1970-01-01
  • 2018-03-02
  • 1970-01-01
  • 2022-07-20
  • 2013-02-12
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多