【问题标题】:What is the C++ equivalent to C's designated initializers?与 C 的指定初始化程序等效的 C++ 是什么?
【发布时间】:2012-06-02 01:49:10
【问题描述】:

您可以像这样在 C 中声明一个结构:

typedef struct MyStruct {
    const char *name;
    int (*func1)(void);
    int (*func2)(void);
    int (*func3)(void);
} MyStruct;

int test_func2(void) {
    return 0;
}

MyStruct test_struct = {
    .name   = "buffer",
    .func2  = test_func2,
};

这对于仅定义特定成员非常方便,所有其他成员都设置为 0/NULL。

编辑:特别是,这允许不知道如何定义 MyStruct 的详细信息,因此它可以在内部更改、添加新成员等。而无需使用此类型破坏代码。

然而,这不会用 C++ 编译器编译,出现错误:

test.c:23: error: expected primary-expression before ‘.’ token
test.c:24: error: expected primary-expression before ‘.’ token

是否有实现相同功能的等效 C++ 声明?

谢谢。

编辑:@chris 我可以告诉你不明白 :) 很明显,大多数其他人评论我应该使用什么语法,应该如何定义结构等等。完全没有抓住重点。这不是关于定义结构的正确方法,这个 sn-p 只是为了提供一个上下文。

至于代码等价, 在代码中的某处说出你所做的:

MyStruct blah = { NULL, NULL, func2 };

现在 MyStruct 将其定义更改为:

typedef struct MyStruct {
  const char *name;
  int (*func4)(void);
  int (*func1)(void);
  int (*func2)(void);
  int (*func3)(void);
} MyStruct;

您的代码仍然可以正常编译,但引入了严重的回归:您现在将初始化 func1 成员,而不是像以前那样设置 func2...

问题是关于 C++ 指定的初始化器是否等效:没有。问题解决了。

【问题讨论】:

  • 在 C++ 中,整个typedef struct A { ... } A; 是毫无意义的。使用这个:struct A { ... };.
  • 这些被称为designated initializers。它们在 C99 中有效,但在 C++ 中无效。
  • @chris,太好了......所以你要在外部使用定义时编写 struct A { ... } ?现在这确实会更有效率!不是。
  • @jyavenard,我不明白。在标头中定义结构并像您一样通过对象使用它。除了标头之外,没有任何内容与结构本身的定义有关。其他文件宁愿定义结构的成员。
  • @jyavenard:在 C++ 中,如果将结构声明为 struct A {...} (或类似的 class A { ... } ),则可以在不使用“结构”或“类”的情况下使用它们。如void foo() { A a = ... } 。这是从 C 到 C++ 的众多重大变化之一

标签: c++ c


【解决方案1】:

不,C++ 不支持 C99 的指定初始化程序。如果要按名称设置单个成员,则需要通过分配来完成,例如

MyStruct test_struct = MyStruct();
test_struct.name  = "buffer";
test_struct.func1 = test_func1;

【讨论】:

  • 不幸的是,这种类型的声明并不总是可行的。特别是如果 test_truct 要在其他地方使用(例如在外部链接代码中)......太糟糕了,没有 C++ 等价物。感谢您的回答
  • @jyavenard:如果test_struct是一个全局变量,你可以定义一个执行初始化并返回初始化对象的函数,然后使用该函数动态初始化全局变量(例如MyStruct test_struct = ConstructTheStruct(); )
【解决方案2】:

正如K-ballo所说,代码相当于:

MyStruct test_struct = {
    "buffer",
    test_func1
};

但是由于您使用的是 C++,您应该考虑为 MyStruct 编写和使用构造函数:

struct MyStruct {
    const char *name;
    int (*func1)(void);
    int (*func2)(void);
    int (*func3)(void);

    MyStruct(const char *n,
        int (*f1)(void) = NULL,
        int (*f2)(void) = NULL,
        int (*f3)(void) = NULL) : name(n), func1(f1), func2(f2), func3(f3) {}
};

请注意,在 C++ 中,您不需要将其 typedef 到 MyStruct,即使没有 typedef,您也可以只使用 MyStruct(不带 struct 关键字)。

【讨论】:

  • 不,它不等效...再次阅读原始问题...当您想要 func2 时,您在这里填充了成员 func1
  • 当我使用 C++ 时,MyStruct 代码实际上是在一个外部库中定义的,用 C 编写。MyStruct 碰巧会不时更改,添加新成员,但并不总是在不幸结束。指定的初始化器可以解决这个问题。
  • @jyavenard:然后将您创建的这些东西包装在工厂函数中,您可以控制谁的界面。这不是一个很难解决的问题。
  • @jyavenard:单独设置每个成员也是如此。当然,语法糖很好,但它没有提供其他情况下不存在的功能。
  • @jyavenard 定义宏,MyStruct_Initializer_n,其中 n 是参数的数量;例如,#define MyStruct_Initializer_3(func1,func2,func3) = { func1, func2, func3 } ... 每个宏的参数数量和顺序永远不会改变,因此您在添加成员时不会冒险引入错误,只要您更改所有宏以正确初始化他们不使用的新成员'不要作为论据。
【解决方案3】:

您可以只使用 lambda(自 C++11 起)。这将允许您保持声明不变,同时轻松初始化结构的全局/常量实例:

struct Test
{
    int x;
    float y;
};

const Test test=[]{ Test t{}; t.x=5, t.y=3.3465; return t; }();

#include <iostream>
int main()
{
    std::cout << "test.x: " << test.x << ", test.y: " << test.y << "\n";
}

您甚至可以将它包装到一个宏中,尽管在下面的表格中它只允许固定数量的初始化器:

// Macro to simplify it a bit
#define DECL_AND_INIT(Type,object,INIT1,INIT2) \
Type object=[]{ Type o{}; o.INIT1; o.INIT2; return o; }()
// Example usage
const DECL_AND_INIT(Test,test1,x=-7,y=-9.325e31);

请注意,您仍然必须在 lambda 中使用像 Test t{}; 这样的值初始化——否则,如果您没有初始化所有成员(例如,由于添加了新成员),您最终会复制导致 UB 的未初始化变量。

【讨论】:

    【解决方案4】:

    与此功能等效的是 struct 的构造函数,其主体为空:

    #ifdef __cplusplus
    MyStruct::MyStruct(char* N, int (*F)(void)) :
        name(N),
        func1(0),
        func2(0),
        func3(F) {
      // empty
    }
    #endif
    

    (以一些语法错误为模,我的 C++ 有点生疏。)

    这在功能上是等效的,因为它允许您构造全局对象,即使它们具有 const 限定字段,并且任何现代编译器都应该在编译时使用静态链接初始化对象。

    【讨论】:

      猜你喜欢
      • 2018-04-22
      • 1970-01-01
      • 1970-01-01
      • 2010-10-25
      • 1970-01-01
      • 2013-03-19
      • 2019-06-26
      • 2010-11-27
      • 2022-01-01
      相关资源
      最近更新 更多