4

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 ints, and not to change it, therefore it has const qualifier in it. I want the function bar to receive an array of ints 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.

Vasily
  • 53
  • 5
  • 2
    please most the full code you need to produce your error message. – Ryan Haining Jun 13 '19 at 23:42
  • "This is foo.cpp" I can already tell you that if that is your foo.cpp, that's not gonna work without reading the rest of the question. See [why templates must be implemented in the header file](https://stackoverflow.com/questions/495021/why-can-templates-only-be-implemented-in-the-header-file). This will cause an undefined reference since, as the linked question states, templates must be defined in the header. –  Jun 14 '19 at 00:09
  • "undefined reference to `void foo(int* const)'" Sure enough, that error is probably because of the reason I mentioned, just a hunch. –  Jun 14 '19 at 00:10
  • 3
    @Chipster The OP is using explicit instantiation; they're just not doing it quite right. Maybe you should have read the rest of the question :) Also the rest of the question you linked to, because "templates must be defined in the header" is _not true_. – Lightness Races in Orbit Jun 14 '19 at 00:11
  • @LightnessRacesinOrbit I'm not sure I understand what you mean. –  Jun 14 '19 at 00:13
  • @LightnessRacesinOrbit Never mind. I read further into the FAQ. I got you now. –  Jun 14 '19 at 00:15
  • 1
    Possible duplicate of [Why can templates only be implemented in the header file?](https://stackoverflow.com/questions/495021/why-can-templates-only-be-implemented-in-the-header-file) –  Jun 14 '19 at 00:16
  • Not quite a dupe (though reading that page wouldn't hurt); there's a good and actually interesting answer to this question, I just don't have time to write it right now. – Lightness Races in Orbit Jun 14 '19 at 00:22
  • @Chipster If I remove all const qualifier the code compiles and runs well. The problem arises only if I try to add const and to call foo from bar. If I add const and call foo from main it works fine. – Vasily Jun 14 '19 at 00:36

1 Answers1

4

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*.

Davis Herring
  • 36,443
  • 4
  • 48
  • 76