Opened 7 years ago
Closed 6 years ago
#11800 closed Bugs (fixed)
Boost Convert fails on user defined types with no value_type
Reported by: | Owned by: | Vladimir Batov | |
---|---|---|---|
Milestone: | To Be Determined | Component: | convert |
Version: | Boost 1.59.0 | Severity: | Problem |
Keywords: | Cc: |
Description
Both the stream and strtol converters seem to make use of is_string which appears to not be using SFINAE correctly resulting in a compilation error ('value_type' : is not a member of 'X').
In 1.59.0 the offending line is boost/convert/detail/is_string.hpp:26.
template<typename T> struct is_string<T, /*is_range_class=*/true> { static bool const value = cnv::is_char<typename T::value_type>::value; };
Change History (10)
comment:1 by , 7 years ago
comment:2 by , 7 years ago
Here is a reproducible using a slightly modified version of the example included with boost convert.
#include <boost/convert.hpp> #include <boost/convert/stream.hpp> //#define VALUE_TYPE value_type #define VALUE_TYPE type struct change { enum VALUE_TYPE { no, up, dn }; change(VALUE_TYPE v =no) : value_(v) {} bool operator==(change v) const { return value_ == v.value_; } VALUE_TYPE value() const { return value_; } private: VALUE_TYPE value_; }; std::istream& operator>>(std::istream& stream, change& chg) { std::string str; stream >> str; /**/ if (str == "up") chg = change::up; else if (str == "dn") chg = change::dn; else if (str == "no") chg = change::no; else stream.setstate(std::ios_base::failbit); return stream; } std::ostream& operator<<(std::ostream& stream, change const& chg) { return stream << (chg == change::up ? "up" : chg == change::dn ? "dn" : "no"); } int main() { boost::cnv::cstream cnv; boost::convert<std::string>(change(change::up), cnv); }
The original uses value_type
but if you change it to something else (as I've done here) you'll get the compilation error in MSVC 2013.
comment:3 by , 7 years ago
Thank you for the analysis and the code snippet. It's much appreciated. Unfortunately, I have no access to MSVC 2013. So, my reasoning is based on the information provided and my looking at the code. There I see that the mentioned code causing compilation error:
template<typename T> struct is_string<T, /*is_range_class=*/true> {
static bool const value = cnv::is_char<typename T::value_type>::value;
};
only kicks in if T is a class (checked by boost::is_class<T>) and T is a range (checked by cnv::is_range<T>). The "struct change" is a class. However, it is not a range and, therefore, cnv::is_range<T> should fail for the class as it does not have begin() and end() methods (see range.hpp lines 19-26). That mentioned check does correctly fail with the compilers (gcc and clang) available to me. More so, judging from http://www.boost.org/development/tests/develop/developer/convert.html, the respective test (convert_test_has_member) also works on msvc-12.0 (aka MSVC-2013, aka BOOST_MSVC=1800) correctly. However, it is known that earlier versions are broken and fail to compile convert_test_has_member.
However, I understand you are using msvc-12.0 (MSVC-2013, BOOST_MSVC=1800) which seems to work in regression tests but fails for you. Could that be that your version of MSVC-2013 needs an update that would bring its behavior in line with msvc-12.0 in the regression tests?
comment:4 by , 7 years ago
I'm using the latest version of Visual Studio 2013 (Version 12.0.40629.00 Update 5). K-ballo in the IRC channel was able to reproduce it as well using Visual Studio 2013.
I've now tested with Visual Studio 2015 Update 1 RC1 and it works fine there so it's definitely a Visual Studio 2013 thing. I can't explain it or why the tests don't catch it, however.
comment:5 by , 7 years ago
Thank you for your reply. It appears I'll have to extend the respective tests and see how Visual Studio 2013 (aka msvc-12.0 in the regression tests) behave. Unfortunately it's lengthy (I'll have to monitor regression tests). Is it a show-stopper for you? Can you work around the problem for now to keep you going? Just to make sure, could you please print out the value of BOOST_MSVC for me please? The reason is that for "BOOST_MSVC < 1800" the respective test is disabled outright in has_member.cpp due to insufficient SFINAE support. However, you indicated that you are using Visual Studio 2013 which (according to https://en.wikipedia.org/wiki/Microsoft_Visual_Studio) should have BOOST_MSVC=1800, i.e. actually run that has_member.cpp test.
Thanks, Vladimir.
comment:6 by , 7 years ago
It is not a showstopper for me. I've just added some self referential value_type typedefs to work around it until I upgrade to VS2015 in the nearish future.
BOOST_MSVC correctly comes out to 1800 for me.
comment:7 by , 7 years ago
Many thanks. I am glad it's not blocking you. That way I'll see what I can do without a hurry.
comment:8 by , 7 years ago
Component: | None → convert |
---|---|
Owner: | set to |
comment:9 by , 6 years ago
Owner: | changed from | to
---|
comment:10 by , 6 years ago
Resolution: | → fixed |
---|---|
Status: | new → closed |
Appears to be MSVC 2013 only. Someone in IRC said 2015 works fine. The check for a range type is what is truly failing, I think.