I have a class that needs to call an external function in a variety of different contexts. I want to keep things flexible, so I'm using an interface (inspired by the 3rd edition of Numerical Recipes) that should work with functors, function pointers, etc. A simplified example looks like:
class MyClass {
public:
template <class T>
MyClass(T &f_) { f = f_; }
private:
int (*f)(int);
};
int myFn(int i) {
return i % 100;
}
int main() {
MyClass test(myFn);
return 0;
}
So far so good; g++ compiles this without any complaints. In my real application, there's a lot more code so I've got things split up among multiple files. For example,
test2.h:
#ifndef __test2__
#define __test2__
class MyClass {
public:
template <class T>
MyClass(T &f_);
private:
int (*f)(int);
};
#endif
test2.cpp:
#include "test2.h"
template <class T>
MyClass::MyClass(T &f_) {
f = f_;
}
main.cpp:
#include "test2.h"
int myFn(int i) {
return i % 100;
}
int main() {
MyClass test(myFn);
return 0;
}
When I try to compile this using g++ test2.cpp main.cpp, I get the following linking error:
/tmp/ccX02soo.o: In function 'main':
main.cpp:(.text+0x43): undefined reference to `MyClass::MyClass<int ()(int)>(int (&)(int))'
collect2: ld returned 1 exit status
It appears that g++ isn't aware of the fact that I'm also trying to compile test2.cpp. Any ideas about what might be going on here?
Thanks,
--craig
Template classes must have their implementation visible to all translation units that use them, unless they are fully specialized.
That means you have to move the implementation in the header:
//test2.h
#ifndef __test2__
#define __test2__
class MyClass {
public:
template <class T>
MyClass(T &f_);
private:
int (*f)(int);
};
template <class T>
MyClass::MyClass(T &f_) {
f = f_;
}
#endif
Related
I've got a problem with a circular dependecy in C++ template methods. I realize there are several similar threads here but they didn't help me with my specific case. This here is a nonsensical example, but it illustrates the issue:
main.cpp
#include "A.h"
int main()
{
float f = 10;
A a;
a.foo( f );
}
A.h
#pragma once
#include "B.h"
#include <iostream>
class A
{
private:
B _b;
public:
A() {}
std::string getName() const { return "A"; }
template<typename T> void foo( T t )
{
if( _b.getActive() )
_b.foo( t, this );
else
std::cout << "A, " << t << std::endl;
}
};
B.h
#pragma once
#include "A.h"
#include <string>
#include <iostream>
class A;
class B
{
private:
bool _active;
public:
B() : _active( false ) {}
bool getActive() const { return _active; }
void setActive( bool active ) { _active = active; }
template<typename T> void foo( T t, const A *a )
{
std::cout << "B, " << a->getName() << std::endl;
}
};
In B.h I can neither forward-declare A (will get error C2039: 'getName': is not a member of 'A'), nor include A.h (will get error C4430: missing type specifier - int assumed.).
Is there a way around this or do I have to completely refactor my code?
EDIT
I'm compiling with MSVC 141 (VS 2017) with /std:c++latest, btw.
The problem here is that getName() in a->getName() is a non-dependent name (it does not depend on the template parameter T), and it is resolved at the point of template definition. But A is incomplete at that point.
As a simple but ugly workaround, we can introduce a fake dependency on T:
template<class T, class S>
struct First {
using Type = T;
};
struct A;
struct B {
template<typename T>
void foo(T t, const typename First<A, T>::Type* a) {
std::cout << "B, " << a->getName() << std::endl;
}
};
A cleaner solution is to move foo() definitions outside classes and include them after both A and B:
// A.h
#pragma once
#include "B.h"
class A {
// ...
template<typename T>
void foo(T t);
};
// A_impl.h
#pragma once
#include "A.h"
template<typename T>
void A::foo(T t) {
// ...
}
// Similar for B.h and B_impl.h
// main.cpp
#include "A_impl.h"
#include "B_impl.h"
int main() {
float f = 10;
A a;
a.foo(f);
}
I'd also like to add a (not so nice) solution, but maybe it's helpful for some:
during investigations it struck me that I had a different project using the same code base which does compile without any issues. I noticed the difference was the new project had the Conformance Mode set to /permissive-, while the old one had not. So if you need a quick solution for MSVC and don't care about standard conformance, you may want to turn this option off. This way, the above code works just as posted.
EDIT
Disclaimer: be aware though that this may break code, as Evg points out in the comment below.
I am getting the error
declaration is incompatible with "void spectrogram<T>::update(<error-type> x)
I don't see any difference between the declaration and the definition of the method, not sure why it is complaining about just this one definition and not the constructor or destructor.
Here is vComplex.hpp
#ifndef VCOMPLEX_H
#define VCOMPLEX_H
template <class T>
class vComplex {
public:
T* realp;
T* imagp;
int length; // for bookkeeping
vComplex(void) { }
vComplex (T* I, T* Q, int len) {
realp = I;
imagp = Q;
length = len;
}
~vComplex(void) {
free(realp);
free(imagp);
}
void put(T* I, T*Q, int len) {
realp = I;
imagp = Q;
length = len;
}
};
#endif
the function declaration for update in spectrogram.hpp, with other members removed:
#ifndef SPECTROGRAM_H
#define SPECTROGRAM_H
template <typename T>
class spectrogram {
public:
void update(vComplex<T> x);
};
#endif
and the function signature (and includes) for update in spectrogram.cpp:
#include <stdio.h>
#include <math.h>
#include "spectrogram.hpp"
#include "vComplex.hpp"
template <typename T>
void spectrogram<T>::update(vComplex<T> x) {
//do stuff
}
In VS 2017, I get the red underline under update and everything inside of it breaks basically. VS is saying T is undefined which I'm assuming is caused by the overall error. I have to use dynamically allocated pointers, I don't have the option of using other types or containers.
I'm implementing some ideas using templates and static members. Although the "real" code produces another error, this is the one which i still have on a toy example code
#include <string>
#include <iostream>
template<int dim>
class Class1 {
public:
Class1() {};
~Class1() {};
void foo() {
std::cout<<"foo-1"<<std::endl;
}
protected:
std::string name;
};
template<int dim>
class Class2 : public Class1<dim>
{
public:
Class2(const int & a, const int &b) :
number( Class2<dim>::id_generator++ )
{
Class1<dim>::name = "My-name";
foo(); // (1)
};
void foo() {
Class1<dim>::foo();
std::cout<<"foo-2"<<std::endl;
}
private:
const unsigned int number;
static unsigned int id_generator;
};
int main()
{
int a = 1, b=2;
Class2<2> class2(a,b); // (2)
}
with the linker error:
undefined reference to `Class2<2>::id_generator'
rea-life example produces 2 errors
(1) required from 'Class2<dim>::Class2(int, int) [with int dim = 3]'
(2) required from here.
that real-life errors tell me absolutely nothing at all! :(
I hope if the toy-problem is solved, the real-life one will be gone too,
but if anyone has any ideas on the "real-life" errors (those 2 lines) in the context of the structure, pls, let me know.
You forgot to add a definition for your static data member id_generator. Add this at global namespace level:
template<int dim>
unsigned int Class2<dim>::id_generator = 0;
With this addition, you can see your code correctly compiling and linking here.
Well, as the error message says, there is no definition of the static data member. If this was an ordinary class, you'd put the definition in a source file:
// header:
class C {
static int i;
};
// source:
int C::i = 3;
A template is a pattern; the compiler uses it to generate code. So what you want to end up with when the compiler instantiates the template is something like the preceding code. But template code goes in headers, not source files, so you write it like this:
// header:
template <class T>
class C {
static int i;
};
template <class T>
int C<T>::i = 3;
If I want to make a template class, and depending on the typeid of the template parameter perform different actions, then how do I code this?
For instance, I have the following template class, in which I want to initialize the member field data depending on whether it is an int or a string.
#include <string>
template <class T>
class A
{
private:
T data;
public:
A();
};
// Implementation of constructor
template <class T>
A<T>::A()
{
if (typeid(T) == typeid(int))
{
data = 1;
}
else if (typeid(T) == typeid(std::string))
{
data = "one";
}
else
{
throw runtime_error("Choose type int or string");
}
}
This code would not compile however, with the following main file.
#include "stdafx.h"
#include "A.h"
#include <string>
int _tmain(int argc, _TCHAR* argv[])
{
A<int> one;
return 0;
}
The error is: error C2440: '=' : cannot convert from 'const char [2]' to 'int', which means the code is actually checking the else-if statement for an int, even though it will never be able to reach that part of the code.
Next, following this example (Perform different methods based on template variable type), I tried the following A.h file, but I got several linker errors mentioning that A(void) is already defined in A.obj.
#include <string>
template <class T>
class A
{
private:
T data;
public:
A();
~A();
};
// Implementation of constructor
template <>
A<int>::A()
{
data = 1;
}
template <>
A<std::string>::A()
{
data = "one";
}
Does anybody know how to get this code up and running? I also realize that using such an if-else statement in a template class might remove the power from a template. Is there a better way to code this?
EDIT: after discussion with Torsten (below), I now have the following A.h file:
#pragma once
#include <string>
// Class definition
template <class T>
class A
{
public:
A();
~A();
private:
T data;
};
// Implementation of initialization
template < class T >
struct initial_data
{
static T data() { throw runtime_error("Choose type int or string"); }
};
template <>
struct initial_data< int >
{
static int data() { return 1; }
};
template <>
struct initial_data< std::string >
{
static std::string data() { return "one"; }
};
// Definition of constructor
template <class T>
A<T>::A()
: data( initial_data< T >::data() )
{
}
and the following main:
#include "stdafx.h"
#include "A.h"
#include <string>
int _tmain(int argc, _TCHAR* argv[])
{
A<int> ione;
return 0;
}
The linker error I now get is: Test template 4.obj : error LNK2019: unresolved external symbol "public: __thiscall A::~A(void)" (??1?$A#H##QAE#XZ) referenced in function _wmain
Explicit specializations are the way to go.
I assume that you are including your A.h in several .cpp, and that's the root cause of your problem.
Specializations are definitions and there must be only one definition of A::A() and A::A() and so they must be in only one .cpp.
You'll have to move the explicit specialization in a .cpp
template <>
A<int>::A()
{
data = 1;
}
template <>
A<std::string>::A()
{
data = "one";
}
and keep a declaration for them in A.h
template<> A<int>::A();
template<> A<std::string>::A();
so that the compiler knows they are explicitly specialized and doesn't try to add automatic one.
Edit: with these four files, g++ m.cpp f.cpp a.cpp doesn't show any errors.
// a.h
#define A_H
#include <string>
template <class T>
class A
{
private:
T data;
public:
A();
};
template<> A<int>::A();
template<> A<std::string>::A();
#endif
// a.cpp
#include "a.h"
template <>
A<int>::A()
{
data = 1;
}
template <>
A<std::string>::A()
{
data = "one";
}
// f.cpp
#include "a.h"
int f()
{
A<int> one;
A<std::string> two;
}
// m.cpp
#include "a.h"
int f();
int main()
{
A<int> one;
A<std::string> two;
f();
}
You are correct in the second solution, what you need is template specialisation (keeping declaration and implementation together):
#include <string>
template <class T>
class A
{
private:
T data;
public:
A();
~A();
};
template <>
class A <std::string>
{
private:
std::string data;
public:
A() { data = "one"; }
};
template <>
class A <int>
{
private:
int data;
public:
A() { data = 1; }
};
If I may suggest a more elegant solution, then I would add a parameter to the constructor and avoid the template specialisation:
template <class T>
class A
{
private:
T data;
public:
A( T value ) : data( value ) {}
virtual ~A() {}
};
In case it's just the c'tor where you want to have behavior that depends on T, I would suggest to factor this out to a different struct:
template < class T >
struct initial_data
{
static T data() { throw runtime_error("Choose type int or string"); }
};
template <>
struct initial_data< int >
{
static int data() { return 1; }
}
template <>
struct initial_data< std::string >
{
static std::string data() { return "1"; }
}
If you specialize a class on it's template parameter, the different specializations are totally different types and can have different sets of data and functions.
Finally:
template <class T>
A<T>::A()
: data( initial_data< T >::data() )
{
}
kind regards
Torsten
The goal of this project is to create a library for distribution. In the past, I used forward declares so I didn't have to distribute a bunch of header files along with the libraries. However, I'm now trying to eliminate code duplication by switching to templates and am running into some issues.
First, a simple example project showing what is currently working:
//LibraryDep1.h
class LibraryDep1
{
public:
LibraryDep1(void) {};
virtual ~LibraryDep1(void) {};
template <typename T>
int TestFunction(T value)
{
std::cout << value << std::endl;
return 0;
}
};
//LibraryInclude.h
class LibraryDep1; //forward declare
class LibraryInclude
{
private:
LibraryDep1* mLibDep1;
public:
LibraryInclude(void);
virtual ~LibraryInclude(void);
int TestFunction(int value);
int TestFunction(std::string value);
};
//LibraryInclude.cpp
#include "LibraryInclude.h"
#include "LibraryDep1.h"
LibraryInclude::LibraryInclude(void)
{
this->mLibDep1 = new LibraryDep1();
}
LibraryInclude::~LibraryInclude(void)
{
delete this->mLibDep1;
}
int LibraryInclude::TestFunction(int value)
{
return this->mLibDep1->TestFunction(value);
}
int LibraryInclude::TestFunction(std::string value)
{
return this->mLibDep1->TestFunction(value);
}
//main.cpp
#include <tchar.h>
#include "LibraryInclude.h"
int _tmain(int argc, _TCHAR* argv[])
{
LibraryInclude inclLibrary;
inclLibrary.TestFunction(77);
inclLibrary.TestFunction("test");
}
This gives the expected output of:
77
test
However, the overloads of LibraryInclude::TestFunction could be replaced with a template function to further reduce code duplication:
//LibraryInclude.h
class LibraryDep1; //forward declare
class LibraryInclude
{
private:
LibraryDep1* mLibDep1;
public:
LibraryInclude(void);
virtual ~LibraryInclude(void);
template <typename T>
int TestFunction(T value) {
return mLibDep1->TestFunction(value);
}
};
The problem now is that I'm using mLibDep1 without including the full implementation giving me an undefined type compilation error. Meaning that I need to #include "LibraryDep1.h" in LibraryInclude.h, thus requiring me to distribute both LibraryInclude.h and LibraryDep1.h with my library. This is a simple example, the real project has many header files that would need to be distributed if I were to switch to using the templated version of LibraryInclude.
My question is, is there any way to avoid having to distribute a bunch of include files with my library and eliminate code duplication? Or, am I better off just overloading for all known types (drastically reducing library flexibility) in the distributed header file and keeping the templates in only the underlying classes?
No. There is currently no way to do what you want. When compiler vendors start implementing the 'export' keyword you'll be in luck. Currently I only know of Comeau doing so. This keyword has been around for years so I wouldn't hold my breath until the rest implement it.
A very limited and ugly solution would be:
//LibraryDep1.h
#pragma once
#include <iostream>
class LibraryDep1
{
public:
LibraryDep1(void) {};
virtual ~LibraryDep1(void) {};
template <typename T>
int TestFunction(T value)
{
std::cout << value << std::endl;
return 0;
}
};
//LibraryInclude.h
#pragma once
class LibraryDep1; //forward declare
class LibraryInclude
{
private:
LibraryDep1* mLibDep1;
public:
LibraryInclude(void);
virtual ~LibraryInclude(void);
template <typename T>
int TestFunction(T value);
};
//LibraryInclude.cpp
#include "LibraryInclude.h"
#include "LibraryDep1.h"
#include <string>
LibraryInclude::LibraryInclude(void)
{
mLibDep1 = new LibraryDep1();
}
LibraryInclude::~LibraryInclude(void)
{
}
// only to save some typing when only forwaring calls
#define LI_TESTFUNCTION( TYPE ) \
template<> \
int LibraryInclude::TestFunction<TYPE>( TYPE value ) {\
return mLibDep1->TestFunction(value); \
}
// the allowed specializations, everything else causes link errors
LI_TESTFUNCTION( int );
LI_TESTFUNCTION( std::string );
Tested this with VC++ 2k8 & g++ 4.3.4 statically linking against LibraryInclude.o