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.
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.
I am trying to do some overload on the template function, following are the examples
do_something.h
template<typename T>
void do_something(T const &input){/*....*/}
void do_something(std::string const &input);
void do_something(boost::container::string const &input);
so far, so good, but what if I want to overload a non-defined type?
like using a type some_type have not defined in the header file
void do_something(some_type const &input);
I want to use it like this
main.cpp
#include "do_something.h"
#include "some_type.h"
#include <boost/container/string.hpp>
int main()
{
do_something(std::string("whatever"));
do_something(boost::container::string("whatever"));
//oops, some_type() never defined in the header file, this
//function will call the template version, but this is not
//the behavior user expected
do_something(some_type());
}
Since some_type is not a POD, not a std::string, boost::container::string.I guess I could designed a traits to do some compile time checking
template<typename T>
typename boost::enable_if<is_some_type<T>::value, T>::type
do_something(T const &input){//.....}
But do I have a better way to do it?
I need compile time type checking, so I use template.All of the types calling this function will do similar jobs based on different types, so I prefer overload.I do not need to save the state, so I prefer function rather than class.
Hope this could help you know more about what I intent to do.Thank you
but what if I want to overload a non-defined type?
You need to provide the declaration of
void do_something(some_type const &input);
before you call do_something with an object of type some_type. Otherwise, the template version will be used.
#include "do_something.h"
#include "some_type.h"
// This is all you need. You can implement the function here
// or any other place of your choice.
void do_something(some_type const &input);
#include <boost/container/string.hpp>
int main()
{
do_something(std::string("whatever"));
do_something(boost::container::string("whatever"));
//oops, some_type() never defined in the header file, this
//function will call the template version, but this is not
//the behavior user expected
do_something(some_type());
}
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.
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.
I want to use a boost::ptr_map inside a specific class which stores instances of itself. However, please consider the following example:
#include <boost/checked_delete.hpp>
#include <boost/ptr_container/ptr_map.hpp>
class foo
{
friend void boost::checked_delete<>(foo*);
~foo() {}
};
int main()
{
boost::checked_delete(new foo); // OK
boost::ptr_map<int, foo> foo_map; // error C2248: 'foo::~foo' : cannot access private member declared in class 'foo'
return 0;
}
The error happens at the following line
// verify that types are complete for increased safety
template<class T> inline void checked_delete(T * x)
{
// intentionally complex - simplification causes regressions
typedef char type_must_be_complete[ sizeof(T)? 1: -1 ];
(void) sizeof(type_must_be_complete);
delete x; // error C2248
}
What exactly is going on here? Shouldn't it work? I assume that the problem is that templates are defined in the compilation unit they are included in and boost::checked_delete is called from another compilation unit in the implementation source of bosst::ptr_map. So, it's not the same function I declared as a friend.
However, is there a workaround for this problem?
Try this syntax when declaring the friend:
template <class T>
friend void boost::checked_delete(T*);
Here is the start of the huge error message* from GCC, which is the start of the chain of instantiations (usually, and in this case):
In file included from main.cpp:1:0:
main.cpp: In function 'void boost::checked_delete(T*) [with T = const foo]':
Adding
friend void boost::checked_delete<>(foo const*);
makes the code compile.
(*): 13 lines and 3510 characters for 270 chars/line