Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/156.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 如何确保调用显式构造函数并允许大括号初始化?_C++_Explicit_List Initialization - Fatal编程技术网

C++ 如何确保调用显式构造函数并允许大括号初始化?

C++ 如何确保调用显式构造函数并允许大括号初始化?,c++,explicit,list-initialization,C++,Explicit,List Initialization,考虑下面的基本程序。它有typedef int Number,目的是允许未来的开发人员将其更改为当时最有意义的精度(甚至可以使用CGAL的一种数字类型) 您可以看到点被描述为一对数字,而线段被描述为两个点 我想实现两个目标: 如果用户试图用除显式编号以外的任何东西实例化点,则应触发编译时警告。我想这就是explicit关键字的作用。相反,正如您在p3的实例化中所看到的,我们默默地允许将浮点转换为int 如果用户希望使用常量值来初始化线段,则只要这些值是数字,就可以进行初始化 我的问题是: 我是否

考虑下面的基本程序。它有
typedef int Number
,目的是允许未来的开发人员将其更改为当时最有意义的精度(甚至可以使用CGAL的一种数字类型)

您可以看到
被描述为一对
数字
,而
线段
被描述为两个

我想实现两个目标:

  • 如果用户试图用除显式编号以外的任何东西实例化
    ,则应触发编译时警告。我想这就是
    explicit
    关键字的作用。相反,正如您在
    p3
    的实例化中所看到的,我们默默地允许将
    浮点
    转换为
    int
  • 如果用户希望使用常量值来初始化
    线段
    ,则只要这些值是
    数字
    ,就可以进行初始化
  • 我的问题是:

  • 我是否误解了应该如何使用
    explicit
  • 期望编译器捕捉到这一点是不可行的吗?换句话说,它是否需要在运行时处于编程逻辑中
  • typedef整数;
    类点
    {
    公众:
    显式点(编号n1,编号n2)
    :x(n1),y(n2)
    {}
    数字x;
    数字y;
    };
    类线段
    {
    公众:
    线段(点p1、点p2)
    :开始(p1),结束(p2)
    {}
    起点;
    点端;
    };
    int main()
    {
    //工作如期进行
    点p1(10,10);
    p2点(20,20);
    线段s1(p1、p2);
    //如何在此处触发编译器错误?
    p3点(10.5,11.5);
    //为什么a不能做到以下几点?
    //线段s2({30,30},{40,40});
    返回0;
    }
    
    是的,您误解了
    明确的
    <构造函数上的code>explicit
    可防止构造函数被用作隐式用户定义转换,例如,当某些内容传递给期望类类型作为参数的函数时。在构造函数上使用
    explicit
    实际上是在阻止
    线段s2({30,30},{40,40})编译就是为了这个确切的原因

    explicit
    不阻止构造函数自身参数中的隐式转换

    使用括号内的初始值设定项语法时,无法避免隐式转换,但可以通过使构造函数成为模板函数并检查其模板参数类型来获得传递的实际类型:

    template<typename T1, typename T2>
    Point(T1 n1, T2 n2)
            : x(n1), y(n2)
    {
        static_assert(std::is_same_v<T1,Number> && std::is_same_v<T2,Number>
            , "Construct Point with Number arguments!");
    }
    
    模板
    点(T1 n1,T2 n2)
    :x(n1),y(n2)
    {
    静态断言(std::is_same_v&&std::is_same_v
    ,“用数字参数构造点!”;
    }
    
    对于
    std::is_v
    和C++17,需要
    #包含
    。(在C++17之前,需要使用
    std::is_same::value


    或者,如果您不想使用错误的类型导致硬错误,您可以使用
    std::enable_if
    而不是
    static_assert

    不相关的注意:在新代码/现代代码中,我个人会避免使用
    typedef
    <代码>使用
    可以完成
    typedef
    所能做的一切(以及更多),因此它有效地取代了它(而且(至少对我来说)更具可读性)。因此,我会制作
    typedef int-Numberbe
    使用Number=int。值得注意的是,我一直在想这个问题。我从来没有真正花时间阅读使用
    ,在编译时失败几次后(由于我的语法错误),我放弃了
    点p{10.5,11.5}
    触发您想要的错误消息。但这并不是因为
    显式
    ,而是因为
    {..}
    对精度的损失更挑剔。@johanneschaub litb你能给我指一下任何我可以阅读更多关于
    MyClass实例{…}
    语法的参考资料吗?这是我第一次看到它。至于最后一行,您已经告诉编译器,两个数字“在概念上”并不等同于一个
    (这是
    显式
    的主要用例,也是它禁用隐式转换的原因)。我想你这样做的原因是,两个数字可能同样意味着“宽度和高度”以及其他许多东西,因此
    显式的
    对我来说似乎是合理的。但是,编译器将禁止您在需要一个点的地方传递两个数字。在您的示例中,是否需要有两个模板参数?期望给定的
    将由两个统一的
    类型的变量表示
    @wesanyer我想这不是真的必要,但是如果您尝试使用两种不同的类型调用它,则不会打印
    静态断言
    中的错误消息。相反,您将得到一个“无匹配重载”错误(与使用
    std::enable_时相同)。