【问题标题】:C++ template accept only typenames with certain memberC++ 模板只接受具有特定成员的类型名
【发布时间】:2021-02-16 19:45:01
【问题描述】:

我正在学习如何使用模板。假设,我有以下类结构。我仅将模板用于tCtD 类(打算在未来实现更多类似的类)。在项目的其他部分,我只使用基类A 中的方法进行抽象。这些类在 VS2019 中可以正确编译和运行。

我的问题是:

  • 是否可以(根据准则和常识)在模板类中引用类型名 T 的成员? (我的意思是getVersion()的实现)
  • 我可以指定类型名 T 需要有这样的成员吗?
struct version {
    const char* name;
    int date;
};

class A {
    virtual void f() = 0;
    virtual const version& getVersion() const = 0;
}

template <typename T>
class B : public A {
   // some methods implementation specific for class B that require using typename T

   void f() override; // implemented somewhere else
   const version& getVersion() const { return T.v; }
}

class tC {
   static constexpr version v{"tC", 1};
   // some methods for C
}

class tD {
   static constexpr version v{"tD", 2};
   // some methods for D
}

【问题讨论】:

  • 这里有几个问题可能会影响实际问题:类/结构声明未以; 结尾,基类A 中没有虚拟析构函数,试图覆盖非虚拟函数在基类中,尝试声明不允许接收此修饰符的 constexpr (至少对于 C++
  • 这是一个最小的编译示例。不幸的是,它有效,这意味着我不知道最初的问题在问什么。 onlinegdb.com/raF_cbBwN 为了使其编译,我需要将 std::string 更改为字符数组,以便 constexpr 有效,并且我还将覆盖的函数在基础中设为虚拟,并将这些部分公开,以便它们可以成为看过,还有其他类似的事情。
  • 是的,所有这些元素都在原始代码中。我笼统地概括了太多,对此感到抱歉。修改了代码。

标签: c++ c++11 templates


【解决方案1】:

你有两个问题:

  • 是否可以在模板类中引用类型名 T 的成员? (我的意思是 getVersion() 的实现)
  • 我可以指定类型名 T 需要有这样的成员吗?

两者的答案都是“是”

在我把你的代码变成一个可编译的例子之后,它会做这两件事(尝试从 tD 中删除 v 的定义,看看它会拒绝那个类)

这是我想出的代码:

#include <stdio.h>

struct version {
    char name[200];
    int date;
};

class A {
public:
    virtual void f() = 0;
    virtual const version& getVersion() const = 0;
};

template <typename T>
class B : public A {
public:
   // some methods implementation specific for class B that require using typename T

   void f() override {};
   const version& getVersion() const override { return T::v; }
};

class tC {
public:
   static constexpr version v{"tC", 1};
   // some methods for C
};

class tD {
public:
   static constexpr version v{"tD", 2};
   // some methods for D
};

int main()
{
    B<tC> btc;
    version vtc = btc.getVersion();
    printf("%s %d\n",vtc.name,vtc.date);

    B<tD> btd;
    version vtd = btd.getVersion();
    printf("%s %d\n",vtd.name,vtd.date);

    return 0;
}

在这里试试:https://onlinegdb.com/raF_cbBwN

【讨论】:

  • 所以仅仅更改为 T::v 就使得 v 成为一个类型所必需的?
  • 没有。 T::v 是您访问任何类型的静态成员的方式——甚至是普通的非模板类。您还可以使用T().v 创建一个T 的临时对象,然后调用该成员。如果没有对象,则不能调用类的成员。尝试只运行 tC.v - 它不起作用,因为 . 不适用于类型。但是tC::v 可以工作,tC c; 后跟c.v 可以工作,tC().v 也可以
  • @PrestigeDrom 抱歉,如果我上次的评论没有通知您 - 我忘了在上面写上您的名字。无论如何,我所说的一个例子是onlinegdb.com/BkBAShYZO
  • 好的,谢谢!所以我的问题很愚蠢。只是想知道我是否违反了任何 c++ 准则,即使它可以编译。感谢您花时间回答我的问题。
  • @PrestigeDrom 我不认为这是一个愚蠢的问题。我想我只是不明白你为什么要问。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-12-12
  • 2020-03-28
  • 2013-05-11
  • 2017-02-19
相关资源
最近更新 更多