C++ 转换运算符到 chrono::duration - 适用于 c++17 但不适用于 C++14 或更低版本

标签 c++ c++14 c++-chrono conversion-operator c++17

以下代码使用设置为 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 内失败。

那么如何解决呢?两种方式:

  1. 将转换运算符标记为const。然而,这将为 mi 选择转换为 int64_t

  2. 将到 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/

相关文章:

c++ - 如何告诉我的程序在等待用户命令时做某事?

c++ - 如何管理标题的#include?

c++ - Windows 中 SO_RCVBUF 的最大值?

templates - 完美转发模板参数包到emplace_back - 编译失败

c++ - 如何为 1970 年 1 月 1 日 00:00:00 创建 std::chrono::time_point?

c++ - 递归 pthread 生成 - 堆栈位置

C++14 - std::revers(ed) std::string 是否在开头包含空字符?

c++ - 如何在 C++14 中实现读/写锁

c++ - 获取错误的毫秒延迟值

C++11 chrono 从数字创建 time_point