bit*_*ask 137 c++ struct initialization
我正在尝试找到一种方便的方法来初始化'pod'C++结构.现在,考虑以下结构:
struct FooBar {
int foo;
float bar;
};
// just to make all examples work in C and C++:
typedef struct FooBar FooBar;
Run Code Online (Sandbox Code Playgroud)
如果我想在C(!)中方便地初始化它,我可以简单地写:
/* A */ FooBar fb = { .foo = 12, .bar = 3.4 }; // illegal C++, legal C
Run Code Online (Sandbox Code Playgroud)
请注意,我想明确地避免使用以下表示法,因为如果我将来更改结构中的任何内容,它会让我感到沮丧:
/* B */ FooBar fb = { 12, 3.4 }; // legal C++, legal C, bad style?
Run Code Online (Sandbox Code Playgroud)
为了实现与/* A */示例中相同(或至少类似)的C++ ,我将不得不实现一个愚蠢的构造函数:
FooBar::FooBar(int foo, float bar) : foo(foo), bar(bar) {}
// ->
/* C */ FooBar fb(12, 3.4);
Run Code Online (Sandbox Code Playgroud)
这对开水有好处,但不适合懒人(懒惰是好事,对吧?).此外,它几乎与/* B */示例一样糟糕,因为它没有明确说明哪个值转到哪个成员.
所以,我的问题基本上是如何/* A */在C++中实现类似或更好的东西?或者,我可以解释为什么我不想这样做(即为什么我的心理范式很糟糕).
编辑
通过方便的,我的意思也是维护和非冗余.
iam*_*ind 40
因为style A在C++中不允许,你不想要style B使用如何style BX:
FooBar fb = { /*.foo=*/ 12, /*.bar=*/ 3.4 }; // :)
Run Code Online (Sandbox Code Playgroud)
至少在某种程度上有所帮助.
iva*_*ult 15
指定的初始化将在c ++ 2a中得到支持,但您不必等待,因为它们在Clang的GCC中得到官方支持.
#include <iostream>
#include <filesystem>
struct hello_world {
const char* hello;
const char* world;
};
int main ()
{
hello_world hw = {
.hello = "hello, ",
.world = "world!"
};
std::cout << hw.hello << hw.world << std::endl;
return 0;
}
Run Code Online (Sandbox Code Playgroud)
你可以使用lambda:
const FooBar fb = [&] {
FooBar fb;
fb.foo = 12;
fb.bar = 3.4;
return fb;
}();
Run Code Online (Sandbox Code Playgroud)
关于这个成语的更多信息可以在Herb Sutter的博客上找到.
你的问题有点困难,因为即使是功能:
static FooBar MakeFooBar(int foo, float bar);
Run Code Online (Sandbox Code Playgroud)
可以称为:
FooBar fb = MakeFooBar(3.4, 5);
Run Code Online (Sandbox Code Playgroud)
因为内置数字类型的促销和转化规则.(C从来没有真正强类型)
在C++中,尽管有模板和静态断言的帮助,但您可以实现的目标是:
template <typename Integer, typename Real>
FooBar MakeFooBar(Integer foo, Real bar) {
static_assert(std::is_same<Integer, int>::value, "foo should be of type int");
static_assert(std::is_same<Real, float>::value, "bar should be of type float");
return { foo, bar };
}
Run Code Online (Sandbox Code Playgroud)
在C中,您可以命名参数,但是您永远不会得到更多.
另一方面,如果你想要的只是命名参数,那么你写了很多繁琐的代码:
struct FooBarMaker {
FooBarMaker(int f): _f(f) {}
FooBar Bar(float b) const { return FooBar(_f, b); }
int _f;
};
static FooBarMaker Foo(int f) { return FooBarMaker(f); }
// Usage
FooBar fb = Foo(5).Bar(3.4);
Run Code Online (Sandbox Code Playgroud)
如果你愿意,你可以在类型促销保护中加油.
将内容提取到描述它们的函数中(基本重构):
FooBar fb = { foo(), bar() };
Run Code Online (Sandbox Code Playgroud)
我知道样式非常接近你不想使用的样式,但它可以更容易地替换常量值并解释它们(因此不需要编辑注释),如果它们改变了那样.
你可以做的另一件事(因为你是懒惰的)是使构造函数内联,所以你不必输入那么多(删除"Foobar ::"和在h和cpp文件之间切换的时间):
struct FooBar {
FooBar(int f, float b) : foo(f), bar(b) {}
int foo;
float bar;
};
Run Code Online (Sandbox Code Playgroud)
许多编译器的C++前端(包括GCC和clang)都理解C初始化器语法.如果可以,只需使用该方法即可.