I have the following code:
foo.h
#include <boost/range/iterator_range.hpp>
#include <string>
inline void foo(const char* s)
{
boost::iterator_range<std::string::const_iterator> r{
s, s + std::char_traits<char>::length(s)
};
(void)r;
}
foo.cpp
#include <foo.h>
#include <boost/range/as_literal.hpp>
// some other code that uses as_literal
boost/range/as_literal.hpp
is included by several headers under boost/algorithm
, including but not limited to
#include <boost/algorithm/string/find.hpp>
#include <boost/algorithm/string/split.hpp>
#include <boost/algorithm/string/join.hpp>
#include <boost/algorithm/string/classification.hpp>
This compiles fine with clang 4.0 and trunk, but fails with GCC 4.8, 7.2 and trunk:
$ g++ -std=c++11 -Wall -pedantic -Wextra -Wformat=2 -Wshadow -Werror foo.cpp
/usr/include/boost/range/detail/str_types.hpp:26:12: error: partial specialization of ‘struct boost::range_const_iterator<T*>’ after instantiation of ‘struct boost::range_const_iterator<const char*, void>’ [-fpermissive]
struct range_const_iterator<T*>
^~~~~~~~~~~~~~~~~~~~~~~~
Now I have a problem because foo.h
cannot tell whether any of the "dangerous" boost headers are included after it. Users of foo.h will get a nasty surprise if they start using any of these headers (or worse, if they were already using those boost headers and add foo.h, their code won't compile - and they're going to complain to me that foo.h is broken).
The only solution I could find was to include boost/range/as_literal.hpp
into foo.h, before the usage of boost::iterator_range
, even though nothing in foo.h needs boost::as_literal
.
This sounds like a bug in boost (1.62), because boost/range/as_literal.hpp
includes boost/range/detail/str_types.hpp
, which contains
namespace boost
{
template< class T >
struct range_const_iterator<T*>
{
typedef const T* type;
};
}
whereas boost/range/iterator_range.hpp
ultimately includes boost/range/const_iterator.hpp
, which contains
namespace boost
{
template< typename C >
struct range_const_iterator_helper
: extract_const_iterator<C>
{};
template<typename C, typename Enabler=void>
struct range_const_iterator
: range_detail::range_const_iterator_helper<
BOOST_DEDUCED_TYPENAME remove_reference<C>::type
>
{
};
} // namespace boost
Defining the same struct with different content can't be right.
Which compiler is right? clang for accepting it or GCC for rejecting it?
Aucun commentaire:
Enregistrer un commentaire