Who is failing, boost, clang, or gcc? Issue with s

2019-06-17 05:50发布

问题:

As noted by this question, boost::asio now can use the C++11 chrono objects if they are available. However, the following code compiles with but not with clang 3.6.0-svn223366-1~exp1

#include <iostream>
#include <boost/chrono.hpp>
#include <boost/bind.hpp>
#include <boost/asio.hpp>
#include <boost/asio/steady_timer.hpp>
#include <chrono>
#include <thread>
#include <functional>

boost::asio::io_service ioservice;
boost::asio::steady_timer timer(ioservice);

void function()
{
    std::cout << "Success" << std::endl;
}

int main()
{
    std::thread t([&]{ ioservice.run(); });
    t.detach();

    timer.expires_from_now(std::chrono::milliseconds(10));
    timer.async_wait(boost::bind(&function));
    std::this_thread::sleep_for(std::chrono::seconds(1));
}

gcc:

~/scratch$ g++ -std=c++11 test_asio_chrono_broken.cpp -lpthread -lboost_system -lboost_chrono
~/scratch$ ./a.out 
Success

gcc and boost are happy to use std::chrono

However, clang:

~/scratch$ clang++-3.6 -std=c++11 test_asio_chrono_broken.cpp -lpthread -lboost_system -lboost_chrono
test_asio_chrono_broken.cpp:23:8: error: no matching member function for call to 'expires_from_now'
    timer.expires_from_now(std::chrono::milliseconds(10));
    ~~~~~~^~~~~~~~~~~~~~~~
/usr/include/boost/asio/basic_waitable_timer.hpp:414:15: note: candidate function not viable: no known conversion from 'std::chrono::milliseconds' (aka 'duration<int64_t, milli>') to 'const duration' (aka 'const duration<boost::int_least64_t, nano>') for 1st argument
  std::size_t expires_from_now(const duration& expiry_time)
              ^
/usr/include/boost/asio/basic_waitable_timer.hpp:387:12: note: candidate function not viable: requires 0 arguments, but 1 was provided
  duration expires_from_now() const
           ^
/usr/include/boost/asio/basic_waitable_timer.hpp:445:15: note: candidate function not viable: requires 2 arguments, but 1 was provided
  std::size_t expires_from_now(const duration& expiry_time,
              ^
1 error generated.

boost::asio is trying to use boost::chrono instead of std::chrono.

Who is at fault here? I would guess that boost is to blame because it has special GCC #ifdef flags for catching c++11 and std::chrono, but that those #ifdefs aren't catching that std::chrono is available when using clang. To whom do I report this issue?

I can fix the code by explicitly defining the timer type (as required by older versions of boost before the automagic std::chrono detection was added). The following change will compile on both gcc and clang

typedef boost::asio::basic_waitable_timer<std::chrono::steady_clock> steady_timer;
steady_timer timer(ioservice);

回答1:

The chrono documentation describes this

Support for the std::chrono facilities is automatically enabled for g++ 4.6 and later, when the -std=c++0x or -std=gnu++0x compiler options are used. (Note that, for g++, the draft-standard monotonic_clock is used in place of steady_clock.) Support may be disabled by defining BOOST_ASIO_DISABLE_STD_CHRONO, or explicitly enabled for other compilers by defining BOOST_ASIO_HAS_STD_CHRONO.

Added emphasis is mine. That said, you can get this working using clang by explicitly defining BOOST_ASIO_HAS_STD_CHRONO

clang++ -D BOOST_ASIO_HAS_STD_CHRONO -std=c++11 test_asio_chrono_broken.cpp -lpthread -lboost_system -lboost_chrono

I don't know if there is precedence supporting clang for stuff like this in other boost libraries, please file a bug.