0

I have a class that I use to apply functions to each element in a vector representing an image.

template <typename T, typename E>
class func1_img_expr_t : public img_expr_t<T> {
public:
    std::function<T(typename E::value_type)> f;
    E e;
    int size, w, h, d;

    func1_img_expr_t(std::function<T(typename E::value_type)> f, const E& e)
        : f(f), e(e), size(e.size), w(e.w), h(e.h), d(e.d) {
    }

    T operator[](int i) const {
        return f(e[i]);
    }

    template <typename E2>
    bool similar(const E2& o) const {
        return e.similar(o);
    }
};

Each function is then defined like this:

    template <typename E>
    auto ceil(const E& e) {
        return func1_img_expr_t<decltype(call(std::declval<typename decltype(to_expr(e))::value_type>())),
                                decltype(to_expr(e))>(
           [](auto e) { return std::ceil(e); }, to_expr(e));
    }

My image type is called img and is templatized so I can have img<float>, img<double> etc., so I can have img<T> foo and call std::ceil(foo); and it will return std::ceil() for every element in the image.

My problem is that elsewhere in the code I have lines such as:

int Lx = std::ceil((nx-1)/2);

(where nx is of type int). This results in a compiler error that the call of the overloaded ceil(int) is ambiguous. I can see why, because if typename E == int then the above is a valid candidate, but obviously it's unnecessary.

The usual advice on eliminating this kind of error (see [here]https://www.geeksforgeeks.org/error-call-of-overloaded-functionx-is-ambiguous-ambiguity-in-function-overloading-in-c/ for example is to typecast the variable (I don't think that would work here as nx is already an int, the issue is that the overloaded call is valid for int) or to remove either one of the functions (well I can't remove std::ceil, and I can't remove my function otherwise I lose the ability to apply it to imgs).

Is there a way (maybe using std::enable_if?) of limiting the applicability of my func1_img_expr_t so that it will only work when passed an img?

Adrian K-B.
  • 99
  • 1
  • 8
  • It looks like you've just discovered why you will do yourself a huge, huge favor if you completely forget that `using namespace std;` exists in C++. But if you insist on using it, then also creating functions with the same name in your namespace as in `std` is guaranteed to end in tears, and frustrations. Although it should be possible to use `std::enable_if` to handle the ambiguity, this is a lot of work all for nothing, and serves only as means of mitigating bad programming practice. The right solution is to get rid of bad programming practices instead of looking for ways to live with them. – Sam Varshavchik Jan 22 '23 at 23:42
  • Your overload can't be in the `std` namespace, so `std::ceil((nx-1)/2)` can't consider your overload. It can't be ambiguous. – user17732522 Jan 22 '23 at 23:42
  • So if I make a namespace `img` and put all my function definitions in that, then when applying them to an `img` call them with e.g. `img::ceil()` it should work? Does the definition of `class func1_img_expr_t` need to be in my new private namespace as well, or just the function definitions? – Adrian K-B. Jan 22 '23 at 23:49
  • @AdrianK-B. The call can't be ambiguous as it is. So I am not sure what you are trying to fix. Even if you are using an unqualified call it can only be ambiguous if you are using `using namespace std;` (which should be avoided). – user17732522 Jan 22 '23 at 23:55
  • But as a general rule: Yes, put classes in your own namespace and functions specific to your class next to the class into the same namespace. That way ADL also works correctly. – user17732522 Jan 22 '23 at 23:57
  • Thanks. I've fixed my code now. If you want to put your comments into an answer I'll happily accept it. – Adrian K-B. Jan 23 '23 at 13:13

0 Answers0