Question

I have a 20-30 line C++ function which was taking a reference to an int for possible updation. Now I am replacing the member which was passed to it with a member of a member encapsulating more data, something like:

searchState.matchedOK = specificSearch(*pageIndices.GetStringIByRef(), searchState); //new, and overwritten.
searchState.matchedOK = specificSearch(pageOffsetInText, searchState); //old

I want to localise this modification to the lines and function called above because the old member should be removed once I have verified equivalence and beyond.

Is this possible with simple casts?

If you want code:

static bool specificSearch(int &matchLocation, const SearchSpecs &specs) {/**/}

and the recently added member:

inline unsigned int *GetStringIByRef() {return &stringI;}
Was it helpful?

Solution

I'm not 100% sure I understand your question, so I might completely miss the mark here. But if you make your function a template:

template<typename IntType>
static bool specificSearch(IntType &matchLocation, const SearchSpecs &specs) {/**/}

That will allow you to pass either type to it.

OTHER TIPS

Your basic problem is that your function specificSearch assigns to an int object. But the thing you want written is an unsigned int object. Fortunately, the strict aliasing rules allows us to write to an unsigned int as if it were an int. The type system doesn't exactly encourage it, but can be persuaded:

searchState.matchedOK = specificSearch(*reinterpret_cast<int*>(pageIndices.GetStringIByRef()), searchState);

This sort-of relies on the value being written to be in the common range of the two types (0 to INT_MAX). I say "sort of", because on 2's complement systems the result of writing a value outside that range is the same as the result of converting the value to unsigned int. On non-2's-complement systems, which in practice don't exist but in principle plague our attempts at portable code, the result is different and hence probably wrong.

It might be better if possible to define an overload of specificSearch:

static bool specificSearch(unsigned int &matchLocation, const SearchSpecs &specs) {
    int loc;
    bool retval = specificSearch(loc, specs);
    if (retval) { // I'm guessing here about the meaning of the return value
        matchLocation = loc; // converts int to unsigned int
    }
    return retval;
}

This assumes that the wrapper function can tell whether or not the "real" specificSearch assigned to loc or not, so that it knows whether or not to assign to matchLocation. If the calling function can't somehow figure that out then this doesn't really work (and if specificSearch is permitted to assign and then throw an exception, you need to account for that too).

It would be more sensible if possible to change stringI to the right type.

You can do this with templates:

template<typename T>
static bool specificSearch(T& matchLocation, const SearchSpecs& specs) {/**/}

And assign to matchLocation inside the function. This way, you can use any type that can be assigned to whatever type it is you're assigning to matchLocation in the function.

If, for some reason, you don't like that, and you want it to only work with int and unsigned int, you can use template specialisation:

// leaving this undefined, which will cause a linker error if you use it with other types
template<typename T>
static bool specificSearch(T& matchLocation, const SearchSpecs& specs);

template<>
static bool specificSearch<int>(int& matchLocation, const SearchSpecs& specs) {
    /* definition */
}

template<>
static bool specificSearch<unsigned int>(unsigned int& matchLocation, const SearchSpecs& specs) {
    // use the other one to avoid code duplication
    int tmp = matchLocation;
    bool retval = specificSearch(tmp, specs);
    matchLocation = tmp;
    return retval;
}

Note that you will probably get warnings for conversions between int and unsigned int using these functions, because the ranges of the two types are different.

I see several issues here. First of all, depending on your intentions it may be better to return merely stringI by value. Otherwise you could adjust its signature as follows:

inline unsigned int &GetStringIByRef() { return stringI; }

in order to make use of C++ references.

As for

static bool specificSearch(int &matchLocation, const SearchSpecs &specs) {/**/}

you would call it then as follows:

searchState.matchedOK = specificSearch(reinterpret_cast<unsigned int&>(pageIndices.GetStringIByRef()), searchState);

Still depends on the object itself (in case it is const), I reckon.

If anything unclear or I missed the point, comment and I'll adjust my answer.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top