C++ 是否有一个C++;类似于C的新声明#

C++ 是否有一个C++;类似于C的新声明#,c++,c++11,c++14,C++,C++11,C++14,我想知道是否有一个新的声明,就像C#for C一样++ C#允许您这样做,它只是稍微整理了一下代码: FuncCall( new Foo() { Bar = "sausage", Boo = 4 } ); 只是我觉得这在C++中有点草率: unique_ptr<Foo> foo( new Foo() ); foo.Bar = "sausage"; foo.Boo = 4; FuncCall( move( foo ) ); 为什么我不将所有参数都放入构造参数? 因

我想知道是否有一个新的声明,就像C#for C一样++

C#允许您这样做,它只是稍微整理了一下代码:

FuncCall( new Foo() {
    Bar = "sausage",
    Boo = 4
} );
只是我觉得这在C++中有点草率:

unique_ptr<Foo> foo( new Foo() );
foo.Bar = "sausage";
foo.Boo = 4;

FuncCall( move( foo ) );
为什么我不将所有参数都放入构造参数?

因为当你必须初始化这么多的时候,这是愚蠢的:


Foo(int-width,int-height,string-title,string-className,string-thjis,string-thjis,stihjjoifger-gfirejgoirejgoirejgoierjgoire)
它将永远持续下去。。。而我的类中已经有了属性。。。所以我只是想知道能不能做到

您可以使用统一初始化来初始化它。

您可以使用lambda:

FuncCall( []{ Foo f; f.Bar = "sausage"; f.Boo = 4; return f; }() );

Foo
必须具有构造函数或聚合类型:

class Foo {
  std::string bar;
  int boo;
public:
  Foo(std::string s, int i) : bar(std::move(s)), boo(i) {}
};

void FuncCall(std::unique_ptr<Foo> ptr) {}

int main() {
  FuncCall(make_unique<Foo>("sausage", 4));
}

请注意以下几点:

class Foo {
    std::string m_bar = "Bar";
    int m_baz = 3;
    float m_boo = 4.2;
    /* ... */
public:
    Foo() {}    // or Foo() = default or elision
};

int main() {
    Foo f;
    f.m_bar = "wunderBar";
}
Foo* fptr = stack_allocate<Foo*>(sizeof(Foo));
// from ctor
fptr->m_bar.string("Bar"); // construct m_bar
fptr->m_baz.int(3);
fptr->m_boo.float(4.2);
// your code:
fptr->m_bar.operator=("wunderBar");
展开为沿着以下几行:

class Foo {
    std::string m_bar = "Bar";
    int m_baz = 3;
    float m_boo = 4.2;
    /* ... */
public:
    Foo() {}    // or Foo() = default or elision
};

int main() {
    Foo f;
    f.m_bar = "wunderBar";
}
Foo* fptr = stack_allocate<Foo*>(sizeof(Foo));
// from ctor
fptr->m_bar.string("Bar"); // construct m_bar
fptr->m_baz.int(3);
fptr->m_boo.float(4.2);
// your code:
fptr->m_bar.operator=("wunderBar");
C++没有提供直接的方法,最接近的机制是默认参数和运算符重载:

class Foo {
    std::string m_bar = "Bar";
    int m_baz = 3;
    float m_boo = 4.2;
public:
    Foo(std::string bar="Bar", int baz=3, int boo=6.1)
        : m_bar(bar), m_baz(baz), m_boo(boo)
        {}
    /* Foo* f = new Foo(); => new Foo(bar="Bar", baz=13, boo=6.1);
     * Foo* f = new Foo("hello"); => new Foo(bar="hello", baz=3, boo=4.2);
     * Foo* f = new Foo("hello", 1, 1.); => new Foo(bar="hello", baz=1, boo=1.);
     * Foo* f = new Foo(42.); => invalid, arguments must be in order.
     */    
};

有关SSCE,请参阅

如果您确实有十几种不同的构造函数配置,那么您可能应该重新考虑您的设计

---编辑---

注意:您不必公开构造函数中的所有参数:

class Foo {
    std::string m_user_supplied;
    std::time_t m_time;
public:
    Foo() : m_user_supplied(), m_time(0) {}
    Foo(std::string src) : m_user_supplied(src), m_time(0) {}
    void addTime(time_t inc) { m_time += inc; }
};
---编辑2---

“也许应该重新考虑你的设计”。。。大型可选参数列表的一个问题是增长。您可能会遇到相互依赖、相互矛盾或相互影响的参数。您可以选择不验证这些,也可以使用复杂的构造函数

struct Foo {
    ...
    FILE* m_output;
    const char* m_mode;
    ...

    Foo(..., FILE* output, const char* mode, ...)
    {
        ...
        if (output != nullptr) {
            ASSERT( output == nullptr || mode != nullptr );
            ... other requirements
        } else {
            if (mode != nullptr)
                ... might not be an error but it might be a bug ...
        }
        ...
    }
};
避免这种情况的一种方法是使用相关成员的封装/聚合

class Foo {
    ...
    struct FileAccess {
        FILE* m_file;
        const char* m_mode;
        constexpr FileAccess() : m_file(nullptr), m_mode(nullptr) noexcept {}
        FileAccess(FILE* file, const char* mode) : m_file(file), m_mode(mode) {
            if (file == nullptr || mode == nullptr)
                throw invalid_argument("file/mode cannot be null");
        }
    };
    ...

    FileAccess m_access;

    Foo(..., FileAccess access, ...);
};
这可以很好地减少肿胀。如果您的API是稳定的,那么您可以将其与初始值设定项列表一起使用(如果您的API不稳定,并且您做了更改,那么更改将咬到您的屁股)

autofoowithfile=make_unique{…,/*access=*/{stdout,“w”},…};
auto-foouwithout=make_-unique{…,/*access=*/{},…};
如果您随后决定停止使用CTOR并切换到使用setter,这将得到相当好的转换,因为您可以重载“set”,它采用各种配置结构之一:

auto foo = make_unique<Foo>();
foo->set(FileAccess(stdout, "w"))
   ->set(Position(Right, -100, Top, 180))
   ->set(DimensionPercentage(80, 75));
auto foo=make_unique();
foo->set(文件访问(stdout,“w”))
->设置(位置(右侧,-100,顶部,180))
->设置(百分比(80,75));
vs

<代码> Auto Foo= MaxuUngess(){伪In,基于IF C++的C语言语法 m_file=stdout; m_mode=“w”; m_xPosition=-100; m_xPositionRel=右; m_位置=-180; m_yPositionRel=顶部; m_维度类型=百分比; m_xDimension=80; m_y尺寸=75; };
以及统一初始化。你也应该调查一下<代码> < <代码>在现代C++代码中很少使用。这很好,但是我没有C++ 14可用在我当前的应用程序中。不过,我想知道C++ 14是否提供了我所要求的:“Foo看起来像这样”,这是一个非常糟糕的方式。仅默认构造函数?这些成员是如何初始化的?为了什么?您的类的用户如何操作它?@Jimmyt1988:如果您不能使用
C++14
,您可以作为一个实用工具;)。如果你不能使用C++14,为什么要给你的问题加上C++14的标签?Foo没有构造函数参数。这实际上更好!我不必把那些废话移到函数中然后。。。嗯哼哼。Lamdba在C++中似乎已经保存了这一天,我讨厌移动所有这些所有权,即使它们被声明在它上面。酷。。。有很大的改进空间,但我现在将u标记为答案。我认为一个智能编译器(阅读:gcc、clang等)将消除lambda调用,并在编译时将其内联?@ColeJohnson我希望如此,但我还没有检查/测量。没有理由编译器不能做它,但是我怀疑任何人都会给你一个保证:)不是我个人做的与你在这里有任何不同,而是我想评论一下,大声地想知道你是否可能无意中在C++中对<代码>结构> /代码>提出了一些神话?这很有帮助!非常感谢你。我猜我必须坚持为我想要初始化的所有参数定义一个庞大的参数列表。。。“哦,这是一种快乐!”光明赛道也许是中国的轨道。因此,为了让读者明白:
struct
class
除了成员和基的默认可访问性外,是完全相同的:
struct
s默认是公共的。我只是在最小化显式可访问性说明符数量的基础上在两者之间进行选择。一些编码标准要求在特定的用例中使用,例如“使用<代码>结构>代码>聚合类型,否则使用<代码>类< /COD> .`jimytt1988:为什么C++类中的“海量海量”?@ JimyMt1988,通常用户不必对初始化对象有太多的了解:类应该注意它,并允许用户最多传递几个参数来配置初始化。如果类只是一个数据块,客户机代码应该控制设置,这在C语言中很常见,那么使用聚合类型。他不是在问关于使用{}的问题,他是在问一个ctor的可选参数。“重新思考你的设计”,我不确定这是否有必要。。。尤其是当所有这些参数都链接到Foo的构造时(或者在我的真实类中,它是一个窗口)。。。我有身高,宽度,头衔,学名,手印。。。但我想分享你的观点是很好的,“也许应该”。另外,我的意思不是字面上的“重新思考”,与“重新开始”不同。IME“重新思考”可以得出一个类似的设计,但差异很小。我参与过几个项目,这些项目都采用了“大结构,填写您需要的内容”的方法,随着它的发展,它有很多缺点,例如冲突的设置和/或相互依赖的值(“baz”没有任何意义,除非
struct Foo {
    ...
    FILE* m_output;
    const char* m_mode;
    ...

    Foo(..., FILE* output, const char* mode, ...)
    {
        ...
        if (output != nullptr) {
            ASSERT( output == nullptr || mode != nullptr );
            ... other requirements
        } else {
            if (mode != nullptr)
                ... might not be an error but it might be a bug ...
        }
        ...
    }
};
class Foo {
    ...
    struct FileAccess {
        FILE* m_file;
        const char* m_mode;
        constexpr FileAccess() : m_file(nullptr), m_mode(nullptr) noexcept {}
        FileAccess(FILE* file, const char* mode) : m_file(file), m_mode(mode) {
            if (file == nullptr || mode == nullptr)
                throw invalid_argument("file/mode cannot be null");
        }
    };
    ...

    FileAccess m_access;

    Foo(..., FileAccess access, ...);
};
auto fooWithFile = make_unique<Foo>{..., /*access=*/{stdout, "w"}, ...};
auto fooWithout  = make_unique<Foo>{..., /*access=*/{}, ...};
auto foo = make_unique<Foo>();
foo->set(FileAccess(stdout, "w"))
   ->set(Position(Right, -100, Top, 180))
   ->set(DimensionPercentage(80, 75));
auto foo = make_unique<Foo>() { # pseudo based on if C++ had the C# syntax
    m_file = stdout;
    m_mode = "w";
    m_xPosition = -100;
    m_xPositionRel = Right;
    m_yPosition = -180;
    m_yPositionRel = Top;
    m_dimensionType = Percentage;
    m_xDimension = 80;
    m_yDimension = 75;
};