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