Const игнорируется в списке параметров функции шаблона - PullRequest
0 голосов
/ 27 апреля 2018

У меня проблема с определениями функций в шаблонных классах.

У меня есть шаблон класса Array с функцией-членом IndexOf:

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

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

    // Other stuff
};

Когда я создаю экземпляр массива с указателем класса, функция игнорирует const T и просто использует T. Поэтому, когда я вызываю функцию с const T, возникает ошибка компилятора: «Нет экземпляра перегруженной функции»:

#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;
}

Код, похоже, забывает , что параметр функции равен const T. Параметр функции должен быть const Object*, но он обрабатывает параметр как его Object*.

Есть идеи, почему это происходит?

Ошибка не возникает, если я не использую указатель в качестве типа.

Код внутри функции не вызовет проблем.

Прежде чем будет сказано, нет, я не буду использовать std::vector или другие подобные, чтобы иметь динамически изменяемый массив. Это убирает все удовольствие.

Ответы [ 3 ]

0 голосов
/ 27 апреля 2018

На самом деле ваше объявление функции можно рассматривать как:

 IndexOf(const (Object *) val)

, что в основном означает, что Object * должен указывать на объект const, как здесь:

 Object *const cobj = new Object();

Теперь у вас будет правильное поведение. Однако, если вас действительно интересуют константные указатели, вам нужно изменить объявление следующим образом:

  Array<const Object *> objects;
0 голосов
/ 27 апреля 2018

Вы можете объявить Array<Object*>::IndexOf() как шаблон:

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

и внутри вы будете сравнивать value с содержимым массива, и это сравнение приведет к приведению содержимого от Object* до const Object*, что, конечно, допустимо.

Также при таком подходе вы можете передавать в эту функцию все, что T можно преобразовать из / в.

0 голосов
/ 27 апреля 2018

const T value, где T равно Object*, равно Object* const value. const в const T value применяется к value и не изменяет T. const T value - это value типа T, который не может быть изменен, что для указателей означает, что нельзя назначить новый адрес. Ясно, что следующая функция не может быть вызвана с const Object *.

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

Чтобы добавить const ness к указанному типу, вы можете использовать черты типа, чтобы получить указываемый тип, добавить к нему const и затем создать из него новый тип указателя. Например:

#include <type_traits>

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

Использование которого будет выглядеть так:

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);
}

Хотя предполагается, что container будет использоваться только с указателями, в этом случае лучше сделать так, чтобы T ссылался на тип объекта, на который указывает объект, а не на тип указателя. Если T может быть или не быть указателем, черта типа может быть улучшена путем проверки, действительно ли T указатель с 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>;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...