【问题标题】:Extend C++ template parameter type names for generated code为生成的代码扩展 C++ 模板参数类型名称
【发布时间】:2020-05-29 15:48:18
【问题描述】:

是否有可能有一个 C++ 模板,其中模板参数可以作为另一个现有(更长)类型名的前缀或后缀。我正在使用从 IDL(接口定义)生成的代码,因此有许多具有相关名称的生成类。例如,如果 IDL 定义了“Foo”,我将生成以下类列表。 Foo, FooReader, FooWriter, FooSerializer, ...

我正在尝试为每个生成的类型创建一个包含成员变量的类...理想情况下,我可以使用Wrapper<Foo> obj; 声明对象

我可以这样做:

#define EXPANDTEMPLATE(type) Wrapper<type, type##Reader, type##Writer, ... >

template <typename T, typename TReader, typename TWriter, ...> class Wrapper {
   T       var1;
   TReader var2;
   TWriter var3;
   ...
};

int main(){
   EXPANDTEMPLATE(Foo) obj;
   //do stuff
}

在我的情况下,默认构造函数不会是一个问题,所以这个工作,但我更喜欢不会导致代码维护者的解决方案跟踪我,打断我的腿。

有没有比创建具有 15 个参数的模板更好/更简洁的解决方案?

【问题讨论】:

  • 通过阅读这个问题,我不知道您要实际做什么,也就是完成。诸如“有没有更好/更清洁的解决方案”之类的问题……除非您解释您要解决的 问题 是什么,否则提问没有意义。例如,使用生成的 IDL 不是问题。在预处理器中的标记上粘贴“Reader”是微不足道的,看起来您知道该怎么做。那你在做什么
  • (...例如在 main 中,obj 这里有成员 var1var2 等;类型为 DataObjectDataObjectReader 等;如果这是你'正在尝试做,obj的类型可以简单地是一个未命名的结构,还是一个std::tuple?)
  • 对象本身将由一个完全实现的类制成,该类包装了 OpenDDS 框架的功能。 问题是我想避免为 IDL 中定义的数百种数据类型输入样板代码,所以我想使用模板类。为了代码的可读性,我不想定义十几个模板参数。由于模板参数本身遵循固定模式,因此我只是在寻找一种简化的技巧来使用。这可能是一个无聊的问题,但仅此而已。
  • 我收集到FooReader 等是由 IDL 工具生成的。我所追求的是(如果是这种情况)你想创建一个包含每个变体成员的对象。另外,你能用这个澄清来编辑这个问题吗? (这应该是问题的一部分;cmets 在 s.o. 上是不稳定的)

标签: c++ macros code-formatting


【解决方案1】:

我唯一想到的就是使用template specialization

代码看起来像

#include <iostream>

using namespace std;

template <typename T>
class Reader;
template <typename T>
class Writer;

template <typename T>
class Wrapper {
    T data;
    Reader<T> reader;
    Writer<T> writer;
};

class Data {};
template<>
class Reader<Data> {};
template<>
class Writer<Data> {};

int main()
{
    Wrapper<Data> wrapper;
    static_cast<void>(wrapper);
} 

【讨论】:

  • 我认为这不是我所需要的,但我明白你在说什么。就我而言,对于“Data”模板参数,我还有一个名为“DataReader”和“DataWriter”的生成类,它不是模板,而是具有固定名称和定义的类。
【解决方案2】:

根据 OpenDDS 文档,here

在文件 TypeTraits.h 中,我们定义了一个模板结构 TypeTraits,以引用与给定数据样本结构相关的各种 DDS 实体。
// TypeTraits.h
模板 
结构类型特征
{
};
 
#define DEFINE_TYPETRAITS(TYPE) \
模板  \
结构类型特征 \
{ \
    typedef TYPE##TypeSupport TypeSupport; \
    typedef TYPE##TypeSupportImpl TypeSupportImpl; \
    typedef TYPE##DataWriter 编写器; \
    typedef TYPE##DataReader 阅读器; \
};
回到 DDSBase,我们现在可以用一个模板参数定义 CreateWriter() 和 CreateReader() 方法......

在这种情况下,您可以使用相同的方法。鉴于上述宏,您可以应用部分模板特化;在您的情况下,通过使用 DEFINE_TYPETRAITS(Foo) 调用此宏。您可能希望自己的宏扩展到您的 15 个变体而不是这些特定的变体,但鉴于这是在 OpenDDS 文档中,它应该是使用它的人更熟悉的方法(理论上)。您的扩展(或默认,如果可行)类型特征类也可能有其他用途。

一旦你有了这个专业(DEFINE_TYPETRAITS你感兴趣的类型),你就可以制作一个像这样的简单模板:

template<typename T>
struct Wrapper
{
    T var1;
    typename TypeTraits<T>::Reader var2;
    typename TypeTraits<T>::Writer var3;
    typename TypeTraits<T>::TypeSupport var4;
    typename TypeTraits<T>::TypeSupportImpl var5;
};

...然后做:

DEFINE_TYPETRAITS(Foo)
int main()
{
    Wrapper<Foo> obj;
}

【讨论】:

  • 这是一个有趣的发现。看起来我不能完全做我希望的事情(即它不是 C++ 的一个特性),但你揭示了另一种将它组合在一起的方法,我绝对可以欣赏.我在生成的标头中看到了一些已定义的 TypeTraits,但我不知道是否可以利用它。我明天试试,谢谢!
  • @Drummerx04 需要注意的是,为了明确这一点......如果您编写自定义宏,您真的也需要自己的自定义 TypeTraits;这是因为现有宏“旨在”被现有宏使用,并且您的代码库中不能有相同专业化的不同形式。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-12-28
  • 2012-01-09
  • 1970-01-01
  • 2010-12-20
  • 2011-05-08
  • 1970-01-01
相关资源
最近更新 更多