C++ 带有另一个构造函数的默认结构

C++ 带有另一个构造函数的默认结构,c++,constructor,initialization,C++,Constructor,Initialization,以下代码未编译,因为实例参数与构造函数参数不匹配。如果我删除构造函数,它将编译并运行。我希望能够以任何一种方式使用它-使用字符串构造或直接成员变量初始化。(这是我真正想做的事情的一个最低版本。)我需要另一个具有初始化列表或类似内容的构造函数吗 具体来说,我不想添加另一个包含两个int的构造函数,我想使用删除字符串构造函数时使用的机制 #include <iostream> #include <string> struct S { int m_a; int

以下代码未编译,因为实例参数与构造函数参数不匹配。如果我删除构造函数,它将编译并运行。我希望能够以任何一种方式使用它-使用字符串构造或直接成员变量初始化。(这是我真正想做的事情的一个最低版本。)我需要另一个具有初始化列表或类似内容的构造函数吗

具体来说,我不想添加另一个包含两个int的构造函数,我想使用删除字符串构造函数时使用的机制

#include <iostream>
#include <string>
struct S
{
    int m_a;
    int m_b;
    
    S(const std::string s):
        m_a(99),
        m_b(99)
    {std::cout << "ctor runs" << std::endl;}
    
    friend std::ostream& operator<<(std::ostream& os, const S& s)
    {  os << "S: " << s.m_a << ", "  << s.m_b; }
};

int main()
{
    S s{1,2};
    std::cout << s << std::endl;
}
#包括
#包括
结构
{
国际货币基金组织;
国际货币基金组织;
S(常量std::字符串S):
m_a(99),
m_b(99)

{std::cout您想要的是不可能的。您的选项有:

  • 不要定义构造函数并使用聚合初始化
  • 为您想要的每一组参数定义构造函数,并实现它们,使其完全按照您想要的方式运行
  • 这些选择是相互排斥的

    我需要另一个具有初始化列表或类似内容的构造函数吗

    您可以定义一个接受
    std::initializer\u list
    的构造函数。这比定义一个接受两个int的构造函数更糟糕

    我想使用删除字符串构造函数时使用的机制

    #include <iostream>
    #include <string>
    struct S
    {
        int m_a;
        int m_b;
        
        S(const std::string s):
            m_a(99),
            m_b(99)
        {std::cout << "ctor runs" << std::endl;}
        
        friend std::ostream& operator<<(std::ostream& os, const S& s)
        {  os << "S: " << s.m_a << ", "  << s.m_b; }
    };
    
    int main()
    {
        S s{1,2};
        std::cout << s << std::endl;
    }
    
    您可以通过删除字符串构造函数来使用该“机制”

    #include <iostream>
    #include <string>
    struct S
    {
        int m_a;
        int m_b;
        
        S(const std::string s):
            m_a(99),
            m_b(99)
        {std::cout << "ctor runs" << std::endl;}
        
        friend std::ostream& operator<<(std::ostream& os, const S& s)
        {  os << "S: " << s.m_a << ", "  << s.m_b; }
    };
    
    int main()
    {
        S s{1,2};
        std::cout << s << std::endl;
    }
    


    另外,您通常应该避免按值传递字符串。

    您不可能想要什么。您的选项包括:

  • 不要定义构造函数并使用聚合初始化
  • 为您想要的每一组参数定义构造函数,并实现它们,使其完全按照您想要的方式运行
  • 这些选择是相互排斥的

    我需要另一个具有初始化列表或类似内容的构造函数吗

    您可以定义一个接受
    std::initializer\u list
    的构造函数。这比定义一个接受两个int的构造函数更糟糕

    我想使用删除字符串构造函数时使用的机制

    #include <iostream>
    #include <string>
    struct S
    {
        int m_a;
        int m_b;
        
        S(const std::string s):
            m_a(99),
            m_b(99)
        {std::cout << "ctor runs" << std::endl;}
        
        friend std::ostream& operator<<(std::ostream& os, const S& s)
        {  os << "S: " << s.m_a << ", "  << s.m_b; }
    };
    
    int main()
    {
        S s{1,2};
        std::cout << s << std::endl;
    }
    
    您可以通过删除字符串构造函数来使用该“机制”

    #include <iostream>
    #include <string>
    struct S
    {
        int m_a;
        int m_b;
        
        S(const std::string s):
            m_a(99),
            m_b(99)
        {std::cout << "ctor runs" << std::endl;}
        
        friend std::ostream& operator<<(std::ostream& os, const S& s)
        {  os << "S: " << s.m_a << ", "  << s.m_b; }
    };
    
    int main()
    {
        S s{1,2};
        std::cout << s << std::endl;
    }
    


    另外,通常应避免按值传递字符串。

    一旦添加了用户提供的构造函数,您的类就不再是聚合。这意味着您不能直接使用

    S s{1,2};
    
    除非您定义了合适的构造函数。在这种情况下,只需添加

    S(int a, int b) : m_a(a), m_b(b) {}
    
    现在可以通过两个
    int
    或任何可以隐式转换为
    int
    的东西来创建
    S

    具体来说,我不想添加另一个包含两个int的构造函数,我想使用删除字符串构造函数时使用的机制

    #include <iostream>
    #include <string>
    struct S
    {
        int m_a;
        int m_b;
        
        S(const std::string s):
            m_a(99),
            m_b(99)
        {std::cout << "ctor runs" << std::endl;}
        
        friend std::ostream& operator<<(std::ostream& os, const S& s)
        {  os << "S: " << s.m_a << ", "  << s.m_b; }
    };
    
    int main()
    {
        S s{1,2};
        std::cout << s << std::endl;
    }
    
    简单地说,这就是接受两个
    int
    的构造函数所做的。它允许您创建对象,就像它是一个聚合一样,即使它不是。也就是说,要获得完全相同的功能,您需要提供如下默认值

    S(int a = 0, int b = 0) : m_a(a), m_b(b) {}
    
    现在呢

    S a{};
    S b{1};
    S c{1, 2};
    
    全部编译,但

    S d{1, 2, 3};
    

    不会。

    一旦添加了用户提供的构造函数,您的类就不再是聚合。这意味着您不能直接使用

    S s{1,2};
    
    除非您定义了合适的构造函数。在这种情况下,只需添加

    S(int a, int b) : m_a(a), m_b(b) {}
    
    现在可以通过两个
    int
    或任何可以隐式转换为
    int
    的东西来创建
    S

    具体来说,我不想添加另一个包含两个int的构造函数,我想使用删除字符串构造函数时使用的机制

    #include <iostream>
    #include <string>
    struct S
    {
        int m_a;
        int m_b;
        
        S(const std::string s):
            m_a(99),
            m_b(99)
        {std::cout << "ctor runs" << std::endl;}
        
        friend std::ostream& operator<<(std::ostream& os, const S& s)
        {  os << "S: " << s.m_a << ", "  << s.m_b; }
    };
    
    int main()
    {
        S s{1,2};
        std::cout << s << std::endl;
    }
    
    简单地说,这就是接受两个
    int
    的构造函数所做的。它允许您创建对象,就像它是一个聚合一样,即使它不是。也就是说,要获得完全相同的功能,您需要提供如下默认值

    S(int a = 0, int b = 0) : m_a(a), m_b(b) {}
    
    现在呢

    S a{};
    S b{1};
    S c{1, 2};
    
    全部编译,但

    S d{1, 2, 3};
    

    不会。

    哪种方式更糟?在这个非常简单的示例中,我会添加第二个构造函数,但实际的结构要复杂得多,而且我已经有了该格式的数据。@NathanPierson如果你传递两个以外的整数,编译器无法检查正确性。另一个问题不适用于整数,但如果更糟糕的是,初始化列表被复制,这对于某些类型来说可能很慢,而对于其他类型则是不允许的。@NathanPierson:
    S{4,8,15,16,23,42};
    没有意义。@Ant拥有一个更复杂的类不会改变你的选项。它们保持不变:要么不定义任何构造函数,要么为你想要的每一组参数定义一个构造函数。更糟糕的是用什么方法呢?在这个非常简单的示例中,我会添加第二个构造函数,但实际的结构要复杂得多,我已经有了该格式的数据。@NathanPierson如果您传递的是两个以外的整数,编译器将无法检查其正确性。另一个不适用于整数的问题,但如果泛化,则是一个问题,即复制了初始化器列表,这对于某些类型可能比较慢,而对于其他类型则是不允许的。@NathanPierson:
    S{4,8,15,16,23,42};
    没有意义。@Ant拥有一个更复杂的类不会改变您的选项。它们保持不变:要么不定义任何构造函数,要么为您想要的每一组参数定义一个。OP声明–具体地说,我不想添加另一个包含两个整数的构造函数。OP声明–具体地说,我不想添加另一个具有两个int的构造函数。如果您删除
    S(const std::string S)
    构造函数,而是执行
    static S make(const std::string S){return S{99,99};}
    class factory函数,您可以拥有所需的聚合构造行为,而无需编写带有两个int的构造函数。类似于只有一个构造函数
    template S(Ts&&…args):m_a(sizeof…(Ts)==2?std::get(std::tie(args…):99),m_a(sizeof…(Ts)==2?std::get(std::tie(args…):99{if(si)