以下代码使用设置为 C++17 的 gcc 7.1.0 进行编译,但不使用设置为 C++14(或 Visual Studio 2017)进行编译。在 Wandbox 上很容易重现.
要让它与 C++11/14 一起工作,必须做些什么?
#include <iostream>
#include <chrono>
int main()
{
struct Convert
{
operator std::chrono::milliseconds()
{
std::cout << "operator std::chrono::milliseconds" << std::endl;
return std::chrono::milliseconds(10);
}
operator int64_t ()
{
std::cout << "operator int64_t" << std::endl;
return 5;
}
};
Convert convert;
std::chrono::milliseconds m(convert);
std::cout << m.count() << std::endl;
int64_t i(convert);
std::cout << i << std::endl;
}
最佳答案
让我们从为什么这在 C++14 中不起作用开始。 std::chrono::duration
有两个相关的c'tors (std::chrono::milliseconds
的别名是):
duration( const duration& ) = default;
template< class Rep2 >
constexpr explicit duration( const Rep2& r );
模板化的参数更适合 Convert
类型的参数。但只有当 Rep2
(又名 Convert
)可隐式转换为 std::chrono::duration
的表示类型时,它才会参与重载决议.对于毫秒
,在Wandbox 上是long
。您的 int64_t
转换运算符使隐式转换成为可能。
但这就是陷阱。对此隐式转换的检查不考虑转换成员函数的 cv 限定符。因此选择了重载,但它通过 const 引用接受。并且您的用户定义的转换运算符不是 const
合格的! @Galik在您的帖子的评论中注明。因此,转换在 毫秒
的c'tor 内失败。
那么如何解决呢?两种方式:
将转换运算符标记为
const
。然而,这将为m
和i
选择转换为int64_t
。将到
int64_t
的转换标记为explicit
。现在,模板化重载不会参与m
的重载决策。
最后,为什么这在 C++17 中有效?那将保证复制省略。由于您的 Convert
具有到 std::chrono::milliseconds
的转换,因此它直接用于初始化 m
。它的细节包括甚至不需要选择复制构造函数,只是稍后将其删除。
关于C++ 转换运算符到 chrono::duration - 适用于 c++17 但不适用于 C++14 或更低版本,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48365690/