【问题标题】:How to specialize a class-member for multiple template values (constants)?如何为多个模板值(常量)专门化一个类成员?
【发布时间】:2017-07-13 07:41:30
【问题描述】:

我想专门化一个模板类的成员方法。此模板类有一个 int 类型的常量模板参数,并且必须根据值选择不同的全局变量:

template <int INSTANCE>
class mailbox
{
public:
    void write(uint32_t v);
}

// global accessors of different instances
extern mailbox<0> mailbox0;
extern mailbox<1> mailbox1;

之后在 .cpp 文件中

template<>
void mailbox<0>::write(uint32_t v)
{
    access(reg_0, v);
}

template<>
void mailbox<1>::write(uint32_t v)
{
    access(reg_1, v);
}

mailbox<0> mailbox0;
mailbox<1> mailbox1;

这让我可以按如下方式使用邮箱:

mailbox0.write(0xdeadcafe);

这会编译和链接。我想通过使用常量 INSTANCE 来简化方法:

template<int INSTANCE>
void mailbox<INSTANCE>::write(uint32_t v)
{
    if (INSTANCE == 0)
        access(reg_0, v);
    else
        access(reg_1, v);
}

但我无法找到正确的语法来使其工作。在保持我的用户代码不变的同时,这是否可能?在 C++ 俚语中,我想做什么的正确词语和术语是什么?

【问题讨论】:

  • template&lt;int INSTANCE&gt; void mailbox&lt;INSTANCE&gt;::write(uint32_t v)
  • 确实知道如何定义模板类的成员函数吗?在非工作示例中,mailbox:: 之间是否缺少某些内容?
  • 如果您当然可以使用 17,我建议您阅读 C++17 的 constexpr if。这应该可以解决您的问题。
  • 我添加了一个用户代码示例,即使请求的版本也不会改变。
  • @MarošBeťko Normal if 如果定义语法正确,在这里可以正常工作。 if constexpr 将通过确保 false 分支不会生成无法访问的代码来帮助优化,否则不会提供语义差异。

标签: c++ templates template-specialization


【解决方案1】:

问题不在于您试图将模板分成 .h 和 .cpp (实际上,在当前标准中这很少可行)?

template <int INSTANCE>
class mailbox
{
public:
    void write(uint32_t v){
        if (INSTANCE == 0)
            access(reg_0, v);
        else
            access(reg_1, v);
    }
}

应该工作

【讨论】:

  • 我想对用户隐藏 reg_0reg_1access
  • 不幸的是,目前这是不可能的。如果您想使用模板,至少这些界面需要可访问。即使在您的第一个示例中,mailbox&lt;2&gt; 也不会编译
  • 这就是目标,有邮箱编译错误或至少链接错误。
  • 那么你的第一个解决方案就是要走的路
【解决方案2】:

也许你可以换一种方式 - 让全局变量成为由同一个 int 邮箱参数化的类的静态成员。例如:

template <int INSTANCE>
struct reg {
    static RegType value;
};

template <int INSTANCE>
RegType reg<INSTANCE>::value;

那么对 reg 值的访问将是透明的,无需任何专门化:

template<int INSTANCE>
void mailbox<INSTANCE>::write(uint32_t v) {
    access(reg<INSTANCE>::value, v);
}

如果c++17在游戏中你可以做一个reg模板全局变量,让代码更简单:

template <int INSTANCE>
RegType reg;

template<int INSTANCE>
void mailbox<INSTANCE>::write(uint32_t v) {
    access(reg<INSTANCE>, v);
}

编辑:

如果您无法修改访问模式,您可以创建引用包装器数组 (c++11):

#include <functional>

std::reference_wrapper<RegType> regs[2] {reg_0, reg_1};

template<int INSTANCE>
void mailbox<INSTANCE>::write(uint32_t v) {
    access(regs[INSTANCE].get(), v);
}

【讨论】:

  • 听起来不错,但 reg_1reg_0access 是按原样提供给我的。我无法改变它。
  • 我现在使用一个简单的const RegType regs[]-array,而不是使用阻止编译器内联代码的 std::reference_wrapper。我用INSTANCE索引它。
  • @PatrickB。只要 regs 在访问之间不可变,这应该对你有用
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-02-20
相关资源
最近更新 更多