[PATCH] [libcxx] Support UDTs convertible to arithmetic types in <cmath>
Eric Fiselier
eric at efcs.ca
Mon Dec 8 20:17:59 PST 2014
The problem I see with this patch is that the expression we use to check for convertibility in `__numeric_type` is often very different from the expression that actually performs the conversion. The expression that checks for convertibility is:
```
__numeric_test(declval<T>());
```
and the expression that actually converts T is:
```
static_cast<T>(t);
```
First, we are checking for implicit conversions and preforming explicit ones. This causes a hard compile error in the following code:
```
struct ImplicitExplicit
{
operator float() { return 0.0; }
private:
explicit operator double() { return 0.0; }
};
// Doesn't fire
static_assert(is_same<
__numeric_type<ImplicitExplicit>::type,float
>::value, "");
ImplicitExplicit value;
// Fails to compile.
double d = static_cast<double>(value);
// Example in cmath:
std::isless(value, (float)0.0); // Compiles
std::isless(value, (double)0.0); // Doesn't compile.
```
Second, we are checking for conversions with rvalue references and preforming conversions with lvalue references. This causes a compile error in the following code:
```
struct RValueConvertible
{
operator double() && { return 0.0; }
};
// Doesn't fire.
static_assert(__numeric_type<RValueConvertible>::value, "");
// Example of error in cmath
RValueConvertible value;
std::isnan(value); // Doesn't compile.
```
Third we copy/move the actual types into the cmath functions before preforming the conversion, but we probably shouldn't do this. The following code will not compile for this reason
```
struct NonCopyable
{
NonCopyable() {}
operator int() { return 1; }
private:
NonCopyable(NonCopyable const &);
};
static_assert(__numeric_type<NonCopyable>::value, ""); // Doesn't fire
NonCopyable value;
std::isnan(value);
```
I'm not sure these problems should hold this patch up, but I would like to see some discussion on it before moving forward.
I think your implementation of std::pow solves each of these problems with a substantial increase in code complexity, but I think with some work a cleaner solution could be reached.
However it seems that every cmath function will have to perfect forward in order to solve all of the problems :(
================
Comment at: include/cmath:944-949
@@ -962,1 +943,8 @@
+pow(_A1&& __lcpp_x, _A2&& __lcpp_y)
+ _NOEXCEPT_
+ (
+ _NOEXCEPT_(__promote<_A1>::__does_not_throw) &&
+ _NOEXCEPT_(__promote<_A2>::__does_not_throw)
+ )
+#endif
{
----------------
Why does `pow` have the noexcept clause on it anyway?
================
Comment at: include/type_traits:1204-1208
@@ -1201,7 +1203,7 @@
template <>
struct __numeric_type<void>
{
- static const bool value = true;
+ static const bool value = true;
};
----------------
My personal preference would be to use a dummy type instead of void for this.
http://reviews.llvm.org/D5942
More information about the cfe-commits
mailing list