3

When I have a numeric type, which defines operator< for double, but not for int, comparision with int literals does not work. This is a problem, as parts of the standard library, i.e. std::complex contain int literals.

Can I make the compiler treat int literals as double when using the type?

Simplified example:

// the defined operator
template<typename T>
bool operator<(const Type<T> &lhs, const T &rhs);

complex<Type<T>> complex_number;
1.0 / complex_number; // this fails

The failure happens inside the _Div method of std::complex at

template<class _Other> inline
void _Div(const complex<_Other>& _Right)
    // ...
    else if ((_Rightimag < 0 ? -_Rightimag : +_Rightimag)

which causes the error:

error C2678: binary '<': no operator found which takes a left-hand operand of type 'Type<T>' (or there is no acceptable conversion)
(...)
complex(665): note: while trying to match the argument list '(Type<T>, int)'
      [
          T=double
      ]

I think probably the code in std::complex should be _Rightimag < static_cast<_Other>(0) to work with all numeric types, but I have to work with what the stdlib provides.

As the other type is from a library as well, I am looking for a way to add the implicit conversion to my code.


For the actual code: I am using ceres, which lets you define functors with a templated scalar type for autodifferentiation. The scalar is both evaluated as T and as Jet<T, N>.

Ceres defines operator<(const Jet<T, N>&, const T&), which allows for jet < 0.0 but not for jet < 0.

In my code I can work around the problem by using doubles or explicitely casting integers to the template type T, but when I try to work with complex<T> I get into trouble for the methods which compare against integer literals, like the _Div method above.

Pete Becker
  • 74,985
  • 8
  • 76
  • 165
allo
  • 3,955
  • 8
  • 40
  • 71
  • You say that you define `operator<` for `double` - but in fact you've defined one that takes an arbitrary type `T`. The root of the problem is that there are two parameters that allow the compiler to deduce `T`, and when the two disagree on what `T` should be, you get an ambiguity. There are ways around that (you place one of the `T`s in non-deduced context) - but it doesn't look like you have control over the declaration of `operator<`. So basically, it's poor design on the part of the authors of that library you use. – Igor Tandetnik Sep 10 '18 at 14:44
  • I have no control over the library instance methods and I am not sure if I can define a conversion operator outside of the class which is then used by classes like ``std::complex``. – allo Sep 10 '18 at 14:48
  • Ceres should define `<` as a friend ADL operator instead of as a free template operator. It would fix your problem. `friend bool operator op(const Jet& f, const T& s) { return f.a op s; }` etc. – Yakk - Adam Nevraumont Sep 10 '18 at 14:57

2 Answers2

5

The std::complex template is not required to work with general types. The Standard says [complex.numbers]/2:

The effect of instantiating the template complex for any type other than float, double, or long double is unspecified.

If you need to generalize any other numeric-like type to a complex-like type, you should be using some different library or implementing your own.

aschepler
  • 70,891
  • 9
  • 107
  • 161
  • This sounds plausible, so I probably need to implement an own complex type with the functions I actually need or use two variables and define functions for the needed operations. – allo Sep 10 '18 at 14:58
  • I wrote an own complex type with the basic operations I need and it works for me. It still feels like something the stdlib should be able to provide, when there is a templated type. On the other hand, ceres needs a lot of explicit casts to its scalar type everywhere, which isn't that nice to work with either. – allo Sep 11 '18 at 15:25
0

Yes, you can get an implicit conversion by defining a constructor that takes a single parameter (of the type you're converting from).

Tim Randall
  • 4,040
  • 1
  • 17
  • 39
  • Can I define this in my code without patching the library? It is open source, but I would like to link against the unmodified library if it is possible. – allo Sep 10 '18 at 14:47
  • 1
    My impression of the question is that all types involved are provided by external libraries and it wouldn't be practical to modify them (such as by adding a constructor). – François Andrieux Sep 10 '18 at 14:49