Here's some simplified code to demonstrate the problem I have.
I have a template function for which I only wish to compile certain fixed instantiations.
The function declarations are:
// *** template.h ***
int square (int x);
double square (double x);
The definitions are:
// *** template.cpp ***
#include "template.h"
// (template definition unusually in a code rather than header file)
template <typename T>
T square (T x)
{
return x*x;
}
// explicit instantiations
template int square (int x);
template float square (float x);
And, an example use is:
// *** main.cpp ***
#include <iostream>
using namespace std;
#include "template.h"
int main (void)
{
cout << square(2) << endl;
cout << square(2.5) << endl;
}
An attempt to compile this results in a link errors, roughly:
main.obj : unresolved external symbol "int square(int)" referenced in function main
I understand what the problem is: the function signatures of my explicit template instantiations do not match those in the header file.
What is the syntax for the (forward) declaration of the explicit template instantiations please? I do not wish to forward declare the template definition, or to move the template definition into a header file.
For what it's worth, I do have a workaround, which is to use wrapper functions, adding the following to the above files:
// *** template.cpp ***
// ...
// wrap them [optionally also inline the templates]
int square (int x) { return square<> (x); }
double square (double x) { return square<> (x); }
That compiles and works as expected. However, this seems like a hack to me. There should be something more elegant than this available in C++ and template syntax.
Any help or hints would be much appreciated.
You need to declare the function template in your header:
template <typename T>
T square(T x);
As you have it now, you declare two nontemplate functions in the header, which are never defined.
There is no other way if you want to hide the template from the header file. You have to have wrapper functions because int square (int x); does not have the same name mangling as template int square (int x); and C++ does not offer you a way to change that.
You can check out how name mingling differs in Visual Studio as an example.
Related
i'm trying to implement a clone of the json serialization library nlohmann::json as a learning experience, and i'm having trouble with the interface for user defined (json<->User type) conversion.
Basically i want the user to be able to overload two function: to_json(json&, const Type&) and from_json(const json&, Type&). Then the library will use overload resolution to call theses function in the templated operator= and one argument constructor.
It works fine when i'm just defining theses function directly but when i try to make a template definition for multiple types (in this example the class S) the linker can't find the definition.
I've tried to explicitly instantiate the function for individual instances of the templated class although i would prefer avoiding having to do that in the final product.
I'm guessing it has to do with the fact that templated function don't have the same signature than free function, but i don't see what i can do to make it work. What am i missing ? I also couldn't find result on google so is it a documented pattern or an anti pattern ?
Thanks you. Below i tried to minimize my problem in one short example.
Class.hpp
#pragma once
#include <cstdio>
template<size_t i>
class S {
size_t n = i;
};
template<size_t i>
void g(const S<i>& s) {
printf("S<%u>\n", i);
}
Class.cpp
#include "Class.hpp"
template void g<10>(const S<10>&); // <-- Even with explicitly instanciation
void g(const bool& b) {
printf("%s\n", b ? "true" : "false");
}
main.cpp
#include "Class.hpp"
template<typename T>
void f(T t) {
extern void g(const T&);
g(t);
}
int main(int, char**) {
S<10> s;
//f(s); <-- linker error: void g(class S<10> const &) not found.
f(false);
}
The name lookup for g in g(t) call stops as soon as it finds extern void g(const T&); declaration; it never sees the declaration of the function template. So the compiler generates a call to a regular non-template function named g taking const S<10>&. But no such function is defined in your program - hence linker error.
This question already has answers here:
undefined reference to template function [duplicate]
(2 answers)
Closed 6 years ago.
I keep getting undefined reference when i call the two functions from my template class "add" and "greater" in my main function.
So, i have:
number.h
#ifndef NUMBER_H
#define NUMBER_H
template <class T>
class number {
public:
T x;
T y;
number (int a, int b){
x=a; y=b;}
int add (T&);
T greater ();
};
#endif
number.cpp
#include "number.h"
template <class T>
int number<T>::add (T& rezAdd){
rezAdd = x+y;
return 1;
}
template <class T>
T number<T>::greater (){
return x>y? x : y;
}
And my main file is: resolver.cpp
#include <stdio.h>
#include <stdlib.h>
#include "number.h"
int main (int argc, char **argv) {
int aux;
number<int> c(3,5);
c.add(aux);
printf ("number added [%d]\n", c.add(aux));
printf ("greater number: [%d]\n", c.greater());
return 0;
}
The errors that i keep getting are:
g++ -Wall -o tema1 resolver.cpp number.cpp
/tmp/ccX483J4.o: In function `main':
resolver.cpp:(.text+0x34): undefined reference to `number<int>::add(int&)'
resolver.cpp:(.text+0x47): undefined reference to `number<int>::add(int&)'
resolver.cpp:(.text+0x64): undefined reference to `number<int>::greater()'
collect2: ld returned 1 exit status
make: *** [all] Error 1
Thanks for the help in advance!
I prefer to have all of my functions in the .cpp file, regardless of whether they are template functions or regular functions. And there is a way to do that with some basic #ifndef magic. Here's what you can do:
main.cpp
#include "myclass.hpp"
int main()
{
// ...
}
myclass.hpp
#ifndef MYCLASS
#define MYCLASS
template<class T>
class MyClass
{
T val;
public:
MyClass(T val_);
}
#define MYCLASS_FUNCTIONS
#include "myclass.cpp"
#endif
myclass.cpp
#ifndef MYCLASS_FUNCTIONS
#include "myclass.hpp"
// regular functions:
// ...
#else
// template functions:
template<class T>
MyClass<T>::MyClass(T val_)
:val(val_)
{}
// ...
#endif
Here's how the precompiler sees it. We have two .cpp files.
When we compile main.cpp we:
include myclass.hpp
check that MYCLASS is undefined, and it is
define it
give compiler the definitions of the generated class (from template class)
include myclass.cpp
define MYCLASS_FUNCTIONS
check if MYCLASS_FUNCTIONS is defined, it is
give compiler the definitions of the generated functions (from template functions)
When we compile myclass.cpp
check if MYCLASS_FUNCTIONS is defined, it isn't
include myclass.hpp
check that MYCLASS is undefined, and it is
define it
give compiler the definitions of the class
include myclass.cpp
include myclass.hpp again
this time MYCLASS is defined so do nothing inside, return to myclass.cpp
check if MYCLASS_FUNCTIONS is defined, it is
give compiler the definition of the generated functions (from template functions)
exit include twice
pass to the compiler all the regular functions
Your class is named wrong. Your class is named cai where all your functions belong to a class named number: http://ideone.com/ZayX0c
One more thing.. you cannot have templates in the .cpp file. Template functions/defintions go in the header along with the class declaration. This is the reason for your undefined function error. Non-template functions go in the .cpp.
#include <cstdio>
#include <cstdlib>
template <class T>
class number {
public:
T x;
T y;
number (int a, int b){
x=a; y=b;}
int add (T&);
T greater ();
};
template <class T>
int number<T>::add (T& rezAdd){
rezAdd = x+y;
return 1;
}
template <class T>
T number<T>::greater (){
return x>y? x : y;
}
int main (int argc, char **argv) {
int aux;
number<int> c(3,5);
c.add(aux);
printf ("number added [%d]\n", c.add(aux));
printf ("greater number: [%d]\n", c.greater());
return 0;
}
Move the definitions of the add and greater function templates into your number.h.
Remember that add and greater aren't functions, they're function templates. To create actual functions, the compiler has to instantiate the template for specific types, such as int, and it can only do that if it has access to the template's definition at the point where it discovers that an instance is needed.
When you compile number.cpp, the compiler has access to the templates' definitions, but it doesn't see any code that requires a specific instance (such as number<int>), so it doesn't generate instances.
When you compile resolver.cpp, the compiler sees that it needs to instantiate those templates for the int type, but it can't since it doesn't have their definitions. So it generates "external references", basically notes telling the linker to look for those functions in some other object file.
The result is that the function templates don't get instantiated in either object file — in one because the compiler didn't know that it should, and in the other because it couldn't — so when the linker goes looking for them (to resolve those external references), it can't find them. That's why you get the error.
Moving the template function definitions into the header makes them visible to the compiler while it's compiling main.cpp, so it's able to instantiate those functions for the int type. Function templates typically need to be defined in header files, rather than .cpp files, for exactly this reason.
I've specified a header file like this:
04-Templates_foo.h:
template <typename T>
class foo {
T x, y;
T getX(void);
void setX(T x);
};
And an implementation like this:
04-Templates_foo.cc:
#include "04-Templates_foo.h"
template <typename T>
T foo::getX(void) {
return this->x;
}
void foo::setX(T x) {
this->x = x;
}
My main routine:
04-Templates.cc
#include <iostream>
#include "04-Templates_foo.cc"
int main (void) {
// Do nothing because it doesn't even compile...
}
Compiling this code returns this error:
In file included from 04-Templates.cc:2:
./04-Templates_foo.cc:4:3: error: expected a class or namespace
T foo::getX(void) {
^
1 error generated.
I can't imagine what the problem is. Why can't I specify the function foo::getX? It's a class name, although the compiler said it is expecting a class and didn't find one :-/
If it may be important. I'm compiling this on a MacBook Pro Retina Mid 2012 with Mavericks.
I used this compile-command:
g++ -o 04-Templates 04-Templates.cc
Suggestions for a better title are welcome ;)
In the definition of foo::getX (and setX as well), what kind of foo?
Because it's a template class, you have to specify that, like
template<typename T>
T foo<T>::getX(void) { ... }
You also have to tell the compiler that member functions are templates for each function in a templated class. So you have to do it for setX as well:
template<typename T>
void foo<T>::setX(T x) { ... }
I have an Apache module (.so) that contains a class I'm trying to completely decouple from Apache itself. The biggest source of frustration is the debug logging. I want to be able to pass the logging function to the class through the template parameters. I can get the proof of concept to work fine when everything is in the same translation unit, but it falls over once they're not because the logging function is an 'undefined reference':
/tmp/ccPdPX2A.o: In function `main':
test.cpp:(.text+0x81): undefined reference to `void C::DoThis<&(LogIt(char const*, ...))>()'
collect2: ld returned 1 exit status
This also happens when Apache tries to load the module containing the class.
The code below reproduces the problem:
// main.cpp
#include <iostream>
#include "C.h"
void LogIt(const char*, ...)
{
std::cout << "GADZOOKS!\n";
}
int main(int argc, char* argv[])
{
C c;
c.DoThis<LogIt>();
}
// C.h
typedef void (*LogFunction)(const char*, ...);
class C
{
public:
template <LogFunction L>
void DoThis();
template <LogFunction L>
void DoThat();
};
// C.cpp
#include "C.h"
template <LogFunction L>
void C::DoThis()
{
L("DoThis!");
DoThat<L>();
}
template <LogFunction L>
void C::DoThat()
{
L("DoThat!");
}
I'd prefer not to have to resort to having the function passed as a function parameter, i.e.
template <typename F>
void C::DoThis(F f)
{
f("DoThis!");
}
because I'd like to structure the code in such a way that the compiler is able to figure out if the body of LogIt is empty (which it will be for Release builds) and not generate any code for the call, and I'd have to pass it as an argument everywhere in the class.
Can it be done?
Okay I recreated everything,
This error undefined reference to void C::DoThis<&(LogIt(char const*, ...))>() is explained here
Now if you do #include "C.cpp" referring above, this will lead to
undefined reference to void C::DoThat<&(LogIt(char const*, ...))>()
So fix:
template <LogFunction L>
void C::DoThat() //Notice :: used here
{
L("DoThat!");
}
and everything complies and execute !
This is because you have your templates invisible at the point where compiler is supposed to instantiate them as you only have a declaration in C.h and a definition in C.c.
Either move template definitions to header or force instantiation in C.c. You will have to provide LogIt declaration in C.c for that.
You need to put template definition in the same as the place where its declared. So that means you need to put your LogIt function where it was declared in the header file. As of right now, we are not able to explicitly separate template declaration and its definition like that.
In moderate-sized or even big complex projects separating template declaration and definition is useful
to reduce compilation time.
However, in a complex code small programmer mistakes may lead to unnoticed behaviour change,
e.g. a generic version is called instead of a specialization.
Example:
Template specialization became invisible due to a missed declaration.
///////////////////// file A.hpp /////////////////////
#include <iostream>
template <typename T>
class A
{
public:
void foo()
{
std::cerr << " calling generic foo " << std::endl ;
}
};
// forgetting following declaration leads to an unintended program behaviour
template <> void A< int >::foo();
///////////////////// file A-foo-int.cpp /////////////////////
#include "A.hpp"
template <>
void A< int >::foo()
{
std::cerr << "calling <int> version of foo" << std::endl;
}
///////////////////// file main.cpp /////////////////////
#include "A.hpp"
int main(int argc , char** argv)
{
A<int>* a = new A<int>();
a->foo();
return 0;
}
///////////////////// Makefile /////////////////////
CC = g++
CPPFLAGS += -Wall -O3
CXXFLAGS += --std=gnu++0x
all: nonrobust-template-setup
nonrobust-template-setup: main.o A-foo-int.o
$(CC) $(CPPFLAGS) main.o A-foo-int.o -o nonrobust-template-setup
clean:
rm -rf *.o nonrobust-template-setup
//////////////////////////////////////////
Question:
is a more robust setup possible (compiler- and platform-independent)
and if, how would it look like?
If not, what is a good way to test that a desired function version is called?
You cannot separate declarations and definitions that way: if you relegate the definition of your specialized member functions in a separate .cpp file, no matter if you declare your specialization immediately after the primary template, the compiler won't be able to instantiate it, and the linker will complain about unresolved references.
Normally, the definition of member functions of a class template goes in a header file, unless you provide an explicit instantiation for the corresponding class templates:
template class X<int>; // You should add this to make your program build,
// or instantiate the corresponding class template
// specialization and invoke the foo() method in the
// same translation unit (A.cpp)
In general, unless you are facing really horrible compilation time issues, I would suggest you to follow the common practice and put everything in a header file to be included by all the translation units that need to use the class template:
///////////////////// file A.hpp /////////////////////
#include <iostream>
template <typename T>
class A
{
public:
void foo()
{
std::cerr << "error: called generic foo " << std::endl ;
}
};
template <>
void A< int >::foo()
{
std::cerr << "calling <int> version of foo" << std::endl;
}
///////////////////// file main.cpp /////////////////////
#include "A.hpp"
int main(int argc , char** argv)
{
A<int>* a = new A<int>();
a->foo();
return 0;
}
If you are facing really horrible compilation time issues, then you could separate the member function definitions and put them into separate translation units with explicit instantiations, but in C++11 there is no clean/easy way to make sure that all the specializations you relegate in separate .cpp files are declared immediately after the primary template (as good practice recommends). If there were, I guess it would be so popular that you wouldn't have needed to come here and ask about it, because everybody faces such a design issue.
In some cases some fancy macros could help, but doubtfully they would bring more benefit than maintenance pain in really complex projects.
A solution to this problem was attempted in the C++03 standard by introducing the export keyword, but implementation experience proved it too hard to support for compiler vendors, which is why export is no more part of the C++ Standard (since C++11).
Hopefully, a better solution for modules will make it into C++14 and provide a solution for template design.
I think the best you can do is to static_assert that the generic template is never instantiated with the types that are supposed to be specialized.
The following code is to illustrate only - I'd probably use BOOST_STATIC_ASSERT (and std::is_same if I could use c++11). The basic idea is to prevent implicitly instantiating the non-specialized template with the set of types you forbid. Of course if you forget to add the static assert AND the specialization you're still going to fail.
template<class T, class U>
struct is_same { enum { value = false }; };
template<class T>
struct is_same<T, T> { enum { value = true }; };
template <bool enable>
struct StaticAsserter
{
char test[enable];
};
template <typename T>
struct foo
{
// Make sure we can't implicit instantiate foo for int.
StaticAsserter<!is_same<int, T>::value> DisallowInt;
};
int main()
{
foo<unsigned> hi;
foo<int> fail;
return 0;
}
The way to be sure of this is to not provide any definition of the generic template's foo(). There's no need to declare specializations when you're doing it this way:
// A.h
template <typename T> struct A { void foo(); };
// main.cc
#include "A.h"
int main ( int c, char **v )
{
A<int>().foo();
// A<long>().foo(); // this line will compile but not link
}
// A.cc
#include <cstdio>
#include "A.h"
template<> void A<int>::foo() { puts("foo!"); }
Okay, from comments instantiating the generic A<T>::foo() implementation is not necessarily an error, only if you have supplied a specialization elsewhere.
So what you want is to find generic-template instantiations whose names duplicate specializations that should only have been instantiated in a specific list of compiler object files -- which reduces to looking for matching fields in two datasets. For that, there's join:
# every object and where it's defined
nm -A *.o | c++filt | grep ' T ' \
| sort -k3 > #all.definitions
# definitions that shouldn't be duplicated:
nm -A A-foo-int.o | c++filt | grep ' T ' \
| sort -k3 > #my.definitions
# everything that shows on both lists:
join -j3 #my.definitions #all.definitions
edit: sed syntax for the grep patterns didn't really work very well.