1

I have created my own floating point types to perform some tests. The goal is that these types can be used out of the box with existing code by just changing a typedef or a template parameter. For example with the Eigen lib I want to be able to do something like Eigen::Matrix<my_type, -1, -1> and do stuff like inverting the matrix etc. To achieve this, I have overloaded all relevant operators and implemented the functions in the math library.

A problem occurs now when the ternary operator is used in the code that should be executed with my types. For example with the Eigen library I get:

error: operands to ‘?:’ have different types ‘my_type’ and ‘double’ 124 | Scalar a = (Mode & UnitDiag) ? Scalar(1) : Scalar(1)/conj(tri(i,i)); | ~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ /usr/include/eigen3/Eigen/src/Core/products/TriangularSolverMatrix.h:124:42: note: and each type can be converted to the other 

I understand that the left and right side of the ':' are different types and the compiler is not sure which one to use, since it would be possible to convert in both directions. But why is it not simply using the result type (Scalar in this case, which is a template parameter)? Is there a way to solve this without changing the implementation of e.g. the Eigen lib? It is not possible to overload the ternary operator and I need the possibility to convert from double to my_type and vice versa.

5
  • 1
    Seems like you could just make it so that my_type::operator/ returns a my_type, not a double, and then both operands would be of type my_type. Commented Jul 26, 2021 at 15:37
  • I agree that it would solve the problem in this case, but I have other occurrences where literals are used, e.g. 1.0 on one of the sides. There the problem would still exist. Commented Jul 26, 2021 at 15:42
  • How would the compiler choose what type to use for the result, ‘my_type’ or ‘double’? Why do you expect it should use ‘my_type’ and not ‘double’? Commented Jul 26, 2021 at 15:50
  • The type of the result of a ternary is well defined, but I forget where it's specified. I'm almost certain this question is a dupe. Commented Jul 26, 2021 at 15:57
  • The result type of the Conditional operator has some complex rules (without involvind the LHS of the assignment operator in the picture) see en.cppreference.com/w/cpp/language/operator_other Commented Jul 26, 2021 at 16:02

1 Answer 1

3

Put it this way:

It should be possible to rewrite your code like so:

auto tmp = (Mode & UnitDiag) ? Scalar(1) : Scalar(1)/conj(tri(i,i)); Scalar a = tmp; 

Since tmp needs to have a defined type of its own, the ternary operator needs to return a consistent type.

In your case, you can force both branches to return the same thing by explicitly casting the branch returning the unexpected type:

Scalar a = (Mode & UnitDiag) ? Scalar(1) : Scalar(Scalar(1)/conj(tri(i,i))); 

Alternatively, you can use a one-shot lambda as a replacement for the ternary operator.

Scalar a = [&]() -> Scalar { if (Mode & UnitDiag) { return Scalar(1); else { return Scalar(1)/conj(tri(i,i)) } }(); 
Sign up to request clarification or add additional context in comments.

1 Comment

Thanks for your answer. My goal was to get around this without touching the code of the library where the conditional operator is used, such that my_type works with templated libraries "out of the box", but this might not be possible.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.