0

In my image class I provide direct memory access to a specific row using the following const overloaded templated functions

template <typename T>
inline T* Image::getRow(unsigned int y)
{
    ...
}

template <typename T>
inline const T* Image::getRow(unsigned int y) const
{
    ...
}

However, if I specify another templated function that actually uses these as:

template <typename T>
void Image::compute(...)
{
    ...
    T* pImageRow = getRow<T>(y); //error C2668
    ...
}

I get the following error error C2668: 'Image::getRow': ambiguous call to overloaded function.

Is there any way to tell the compiler that it should actually use the non-const variant of Image::getRow?`

Minimal Example

Working on an reproducible example, I found out that the problem is appearantly somewhat deeper (actually if I call getRow from a lambda function parallelFor):

Minimal example is here:


inline void parallelFor(unsigned int endIndex, const std::function<void(unsigned int i)>& computeFunction, unsigned int startIdx = 0)
{
    #pragma omp parallel for
    for(int i = startIdx; i < (int)endIndex; i++)
    {
        computeFunction((unsigned int)i);
    }
}

class Image
{
public:
    template <typename T>
    T* getRow(unsigned int y);
    template <typename T>
    const T* getRow(unsigned int y) const;
    template <typename T>
    void compute(const std::function<void(unsigned int x, unsigned int y, T& data)>& computeFunction);
};

template <typename T>
inline T* Image::getRow(unsigned int y)
{
    return (T*)nullptr;
}

template <typename T>
inline const T* Image::getRow(unsigned int y) const
{
    return (const T*)nullptr;
}

template <typename T>
void Image::compute(const std::function<void(unsigned int x, unsigned int y, T& data)>& computeFunction)
{
    unsigned int rows = 10;
    unsigned int cols = 10;

    parallelFor(rows,
        [&](unsigned int y)
        {
            T* pImageRow = getRow<T>(y);
            for(unsigned int x = 0; x < cols; x++)
            {
                T& curVal = pImageRow[x];
                computeFunction(x, y, curVal);
            }
        });
}

int main(int argc, char** argv)
{
    Image a;
    a.compute<unsigned char>([](unsigned int x, unsigned int y, unsigned char& color) { color = 0; });

    return 0;
}
RatTac
  • 37
  • 3
  • 5
    Can we get a [mre]? – NathanOliver Apr 09 '21 at 14:08
  • 1
    Can't reproduce the error on [godbolt](https://godbolt.org/z/Wr1xvoqa5), please provide a reproducible example. – Yksisarvinen Apr 09 '21 at 14:21
  • @NathanOliver *yes we can...* – anastaciu Apr 09 '21 at 14:25
  • Thx for the remarks using a minimal reproducible example. Actually, while assembling the example it seems that the problem is somewhat deeper. I updated the question. – RatTac Apr 09 '21 at 14:34
  • Okay, I'm afraid my knowledge about templates is not enough to tell "why", but adding `this->` to the call fixes the problem. (GCC and clang works with and without that): https://godbolt.org/z/71zdf4Yra – Yksisarvinen Apr 09 '21 at 14:39
  • @Yksisarvinen: Haha, indeed ;) Would be interesting why this is the case.... Is this a bug of Visual Studio Compiler? – RatTac Apr 09 '21 at 14:41
  • It could be a bug in MSVC (or extension in GCC/clang). [This question](https://stackoverflow.com/questions/993352/when-should-i-make-explicit-use-of-the-this-pointer) mentions a case when `this` is needed in template classes, but that's a somewhat different situation. – Yksisarvinen Apr 09 '21 at 14:45
  • @Yksisarvinen: If you want to post it as the solution, I'd be happy to accept it. Otherwise I could answer it myself if someone else stumbles upon a similar issue. – RatTac Apr 09 '21 at 16:29

2 Answers2

0

Add const to void Image::compute(...)

void Image::compute(...) const

If this is not possible but t can point a const, then do

template <typename T>
void Image::compute(...)
{
    ...
    const T* pImageRow = static_cast<const Image*>(this)->getRow<T>(y);
    ...
}

If both are not possible then add a second dummy parameter to one of the overloaded.

273K
  • 29,503
  • 10
  • 41
  • 64
0

As it turned out, it could very well be a bug in MSVC, as other compilers don't have problems with this.

@Yksisarvinen mentioned in a comment that the error can be fixed by using this->getRow<T>(y) instead of getRow<T>(y). This solves it for MSVC.

RatTac
  • 37
  • 3