const квалификатор для вложенных шаблонных функций в c ++ - PullRequest
3 голосов
/ 14 июня 2019

Я хочу, чтобы функция шаблона bar вызывала функцию шаблона foo с квалификатором const .

У меня есть два шаблона для функций foo и bar с их экземплярами.Это foo.cpp

#include "foo.h"
#include <iostream>

template <class T>
void foo(const T x){
    std::cout<<x[0]<<std::endl;
};
// instantiation here, in order to avoid implementation in header
template void foo<const int*>(const int*);

foo.h :

template <class T>
void foo(T x);

bar.cpp :

#include "bar.h"
#include "foo.h"
#include <iostream>

template <class T>
void bar(T x){
    foo<const T>(x);
};
// instantiation here, in order to avoid implementation in header
template void bar<int*>(int*);

и bar.h :

template <class T>
void bar(T x);

наконец, main.cpp :

#include <iostream>
#include "bar.h"
#include "foo.h"
int main()
{
    int p[5];
    p[0]=17;
    foo(p);
    bar(p);
    return 0;
}

Все.h файлы содержат # ifndef / # определяют стандартные операторы.Функция foo должна получить массив int s, а не изменять его, поэтому в ней есть квалификатор const .Я хочу, чтобы функция bar получила массив int s и изменила его, в какой-то момент она также должна вызвать функцию foo .Причина использования шаблона заключается в том, что в будущем я хочу вызывать эти функции для различных типов данных, таких как double *, std :: vector & и т. Д.

Когда я пытаюсь скомпилировать, я получаю следующую ошибку:

undefined reference to `void foo<int* const>(int* const)'

, как будто он не может привести int * к const int *,Кроме того, он, кажется, заменяет указатель на const int на const указатель на int.Любая идея, как я могу справиться с этим?

Еще одно наблюдение: если я удаляю foo.cpp и bar.cpp и вместо этого сливаю все в один файл, который он компилируетобычно.

=========================================

Дело решено

Реализация для foo выполнена для .Как заметили люди, когда foo вызывается в bar , const T приводится к T const == int * const , что не являетсятак же, как const int *.

Чтобы превратить его в int const *, я добавил к коду:

typedef typename std::remove_pointer<T>::type tmp_type; // tmp_type = int
foo<tmp_type const *>(x);

Youнужно -std = c ++ 11, чтобы скомпилировать это.В качестве альтернативы, как предложил Дэвис Херринг, вы можете вместо этого использовать

foo<const std::remove_pointer_t<T>*>(x);

, но для этого вам нужно будет использовать -std = c ++ 14.

Проблема не имеет ничего общего среализация шаблонов в заголовочном файле, за исключением очевидного наблюдения, что ничего этого не требуется, если все находится в одном файле.

Другое решение состоит в том, чтобы иметь два экземпляра для foo:

template void foo<int const *>(int const *);
template void foo<int *>(int *);

где первый не позволяет вам изменить значение указателя внутри функции, а второй позволяет вам передать в него просто int *.

1 Ответ

4 голосов
/ 14 июня 2019

Если T равно int*, const T равно int *const, а не const int*. (В конце концов, учитывая

typedef const T cT;
cT t1=/*…*/,t2=/*…*/;

запрещено t1=t2, а не *t1=*t2.)

Вы можете использовать const std::remove_pointer_t<T>* для построения const int* из int*.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...