Braddock Bres
Braddock Bres

Reputation: 32

Const being ignored in template function parameter list

I'm having a problem with function definitions in template classes.

I have a template class Array that has a member function IndexOf:

// Defined in header
template <typename T>
class Array {
    // Other stuff

    int IndexOf(const T value) const {
        // Code of function
    };

    // Other stuff
};

When I create an instance of the array with a class pointer, The function ignores the const T and just uses T. So when I call the function with a const T, there is a compiler error: "No instance of overloaded function":

#include "Array.h"

class Object{
    // Object stuff
};

int main(){
    // Demonstration code
    Array<Object*> objects = Array<Object*>(); // Array of Object*
    Object* obj = new Object();                // An Object*
    const Object* cobj = new Object();         // A const Object*

    // This works fine
    objects.IndexOf(obj); // No problems

    // This has compile error
    objects.IndexOf(cobj); // No idea why

    delete obj;
    delete cobj;

    return 0;
}

The code seems to forget that the function's parameter is const T. The function parameter should be const Object*, but it treats the parameter like its just Object*.

Any idea why this happens?

The error does not occur if I am not using a pointer as the type.

The code inside the function would not cause problems.

Before it is said, no, I will not use std::vector or others of the like to have a dynamically resizing array. That takes all the fun out of it.

Upvotes: 0

Views: 149

Answers (3)

Anton Savin
Anton Savin

Reputation: 41331

You can declare Array<Object*>::IndexOf() as template:

template <typename U>
int IndexOf(const U& value) const {
    // Code of function
}

and inside you'll compare value to the contents of the array and that comparison will cast the contents from Object* to const Object* which is of course allowed.

Also with this approach you can pass to that function anything that T can be converted from/to.

Upvotes: 0

Serge
Serge

Reputation: 12384

In reality your declaration of the function can be seen as:

 IndexOf(const (Object *) val)

which basically means that the Object * should point to the const object as here:

 Object *const cobj = new Object();

Now you will have correct behavior. However if you are really interested in const pointers, then you need to modify your declaration as:

  Array<const Object *> objects;

Upvotes: 2

Fran&#231;ois Andrieux
Fran&#231;ois Andrieux

Reputation: 29072

const T value where T is Object* is Object* const value. The const in const T value applies to value and does not modify T. const T value is a value of type T that can't change, which for pointers means can't be assigned a new address. It's clear that the following function could not be called with a const Object *.

int IndexOf(Object * const value) const // const pointer to non-const Object

To add constness to the pointed-to type, you can use type-traits to get the pointed-to type, add const to it and then produce a new pointer type from it. For example :

#include <type_traits>

template<class T>
using add_const_to_ptr =
    std::add_pointer_t<
    std::add_const_t<
    std::remove_pointer_t<T>>>;

The usage of which would look like :

template<class T>
struct container {
    void push(add_const_to_ptr<T> ptr) {
        (void)ptr;
    }
};

struct bar {};

int main()
{
    const bar cbar;
    bar mbar;

    container<bar*> my_container;

    my_container.push(&mbar);
    my_container.push(&cbar);
}

Though this assumes container will only be used with pointers, in which case it may be better to make T refer to the type of object pointed to, rather than a pointer type. If T may or may not be a pointer type, the type trait can be improved by checking if T is actually a pointer with std::conditional :

#include <type_traits>
template<class T>
using add_const_to_ptr =
std::conditional_t<std::is_pointer<T>::value,
    std::add_pointer_t<
    std::add_const_t<
    std::remove_pointer_t<T>>>,
    T>;

Upvotes: 0

Related Questions