简体   繁体   中英

const qualifier for nested template functions in c++

I want a template function bar to call a template function foo with const qualifier.

I have two templates for functions foo and bar with their instantiations. This is 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*);

and bar.h :

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

finally, main.cpp :

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

All .h files contain #ifndef/#define standard statements. Function foo is supposed to get an array of int s, and not to change it, therefore it has const qualifier in it. I want the function bar to receive an array of int s and change it, while at some point it should call function foo also. The reason for template use is that in the future I want to call these functions for different types of data, such as double* , std::vector< int >& , etc.

When I try to compile, I get the following error:

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

as if it cannot cast int* to const int* . Also, it seems to replace pointer to const int to const pointer to int. Any idea how I can deal with it?

One more observation: if I remove foo.cpp and bar.cpp and instead merge everything in one file it compiles normally.

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

Case solved

Instantiation for foo is done for < const int* > . As people noticed, when foo is called in bar , const T casted to T const == int * const that is not the same as const int* .

In order to turn it to int const* , I added to the code:

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

You need -std=c++11 to compile that. Alternatively, as Davis Herring proposed, you can use

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

instead, but you will need to use -std=c++14 for this.

The problem had nothing to do with implementation of templates in header file, except for the obvious observation that none of that is needed if everything is in one file.

The other solution is to have two instantiations for foo:

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

where the first one does not let you change the value of the pointer inside the function, while the second one lets you pass just simple int* in it.

If T is int* , const T is int *const , not const int* . (After all, given

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

it's t1=t2 that's forbidden, not *t1=*t2 .)

You can use const std::remove_pointer_t<T>* to construct const int* from int* .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM