I have a lib which I want to test using google test framework. The code is very old and I can't change anything in actual code.
I have included a header file first.h which have following typedef:
typedef struct aList* aList;
and in another file, say second.c, struct is defined as:
struct aList {
aRecord* top;
};
and in my TestFile.cc:
#include "gtest/gtest.h"
#include "First.h"
TEST(First_Test, Create)
{
FuncName();
}
when I compile it using:
g++ -isystem ../../../test/framework/gtest/googletest/include -isystem ../../../test/framework/gtest/googlemock/include -g -Wall -Wextra -pthread --coverage -Iinclude/path -c TestFile.cc -Lpath/to/lib -llibfile
I get following error:
error: conflicting declaration typedef struct aList* aList
error: struct aList has a previous declaration as struct aList
There are no include guards in header files. But I don't think issue is because of that.
Any clue how to fix this?
EDIT
Here is a complete verifiable example.
Contents of FirstFile.h:
#include "SecondFile.h"
typedef struct aList* aList;
void func();
Contents of FirstFile.c:
#include "FirstFile.h"
void func()
{
}
void main()
{
func();
}
Contents of SecondFile.h:
struct aList {
int* top;
};
Contents of TestCode.cc:
#include "FirstFile.h"
void funcTest()
{
func();
}
Command to compile:
g++ TestCode.cc -o TestCode
unfortunately some little devil in your company has managed to get non-conforming c++ code into your libraries.
Simply trying to compile this:
struct aList {};
typedef struct aList* aList;
results in:
2 : error: conflicting declaration 'typedef struct aList* aList'
typedef struct aList* aList;
^
1 : note: previous declaration as 'struct aList'
struct aList {};
I am afraid you are compelled to fix the faulty library.
Related
I am trying to use the boost multi_array, it works in my main driver code, however when I try to use it in a header file of mine it gives me the following error:
error: no type named 'extents' in namespace 'boost'
main.cpp
#include <boost/multi_array.hpp>
int main()
{
boost::multi_array<double, 3> A(boost::extents[2][2][2]);
return 0;
}
the following works
c++ -I /usr/local/include/ main.cpp
./a.out
however, using a header file doesn't.
my_header.hpp
#include <boost/multi_array.hpp>
my_class
{
private:
boost::multi_array<double, 3> A(boost::extents[2][2][2]);
public:
my_class();
};
my_header.cpp
#include "my_header.hpp"
#include <iostream>
my_class::my_class()
{
std::cout << "Test" << std::endl;
}
i.e.
c++ -I /usr/local/include/ -c my_header.cpp
gives:
./my_header.hpp:6:42: error: no type named 'extents' in namespace 'boost'
The error message is confusing but really your syntax is incorrect. Try this
class my_class
{
private:
boost::multi_array<double, 3> A;
public:
my_class() : A(boost::extents[2][2][2]) {}
};
Consider a program consists of files AA.hpp, A1.hpp, A1.cpp, and main.cpp compiled with g++ -std=c++11 main.cpp A1.cpp.
// file AA.hpp
template < int > struct AA;
// file A1.hpp
#include "AA.hpp"
template <> struct AA<1> { /*implementation goes here...*/ };
extern template struct AA<1>;
// file A1.cpp
#include "A1.hpp"
template struct AA<1>;
// file main.cpp
#include "A1.hpp"
int main()
{
AA<1> a1;
// use a1 ...
return 0;
}
Compare this with a scenario when there is no A1.cpp and there is no explicit instantiation declaration in A1.hpp. Will I get any compilation time benefits in the first scenario? And why?
Another question. What if I make a shared library of A1.cpp by g++ -std=c++11 -shared -o libA1.so A1.cpp and then make executable with g++ -std=c++11 -lA1 main.cpp? Will the calls of A1's functions in man.cpp refer to the code in libA1.so or they will be generated (inlined or not) in the executable?
Bellow code is successfully compiling at Visual studio & Solaris compiler. But getting the link error at g++ (SUSE Linux) 4.3.4. Please let me know how to fix this link error at linux?
Note: To make code simple and cleaner I have typed proxy code here.
//---------------- a1.h -----------
#ifndef __a1_h__
#define __a1_h__
#include <iostream>
#include <memory>
namespace ServiceManagement
{
template <typename T>
class ClassA1
{
public:
ClassA1() {}
typedef std::auto_ptr<T>(*addFunc)(int, int);
static void setAddFunc(addFunc f)
{
s_AddFunc = f;
}
private:
static addFunc s_AddFunc;
};
}
#endif
//---------------- b1.h -----------
#ifndef __b11_h__
#define __b11_h__
#include "a1.h"
typedef ServiceManagement::ClassA1<int> setPosType;
namespace ServiceManagement
{
class ClassB1
{
public:
ClassB1() {}
static void Register();
private:
std::auto_ptr<setPosType> m_ptrMsg;
};
}
#endif
//---------------- b1.cpp -----------
#include "b1.h"
#include <iostream>
using namespace std;
//setPosType::addFunc setPosType::s_AddFunc;
template <> setPosType::addFunc setPosType::s_AddFunc;
namespace AA
{
namespace v2
{
std::auto_ptr<int> message2_(int a, int b)
{
int c = a + b;
std::auto_ptr<int> p1(new int);
*p1.get() = c;
return p1;
}
}
}
namespace ServiceManagement
{
void ClassB1::Register()
{
setPosType::addFunc f1 = ::AA::v2::message2_;
setPosType::setAddFunc(f1);
}
}
int main()
{
int i = 0;
cin >> i;
return 0;
}
Link Error:
/usr/bin/c++ -pthread -g -w -W -Wall -Wno-long-long -g -ldl -lm -lnsl -m64 -o -pthread -std=gnu++0x -Bdynamic
.. build " CMakeFiles/templateTest.dir/b1.cpp.o -o ../../../../../..//templateTest -rdynamic
CMakeFiles/templateTest.dir/b1.cpp.o: In function **ServiceManagement::ClassA1<int>::setAddFunc(std::auto_ptr<int> (*)(int, int))'**:
/templateTest/**a1.h:18: undefined reference toServiceManagement::ClassA1::s_AddFunc'
collect2: ld returned 1 exit status**
Note 2:
already static variable is defined at b1.cpp like below,
template <> setPosType::addFunc setPosType::s_AddFunc;
1.) It works once you initialize the member variable:
template <> setPosType::addFunc setPosType::s_AddFunc = 0;
Obviously, without the initializer, this line is a declaration rather than a definition, but, honestly, I do not see why.
2.) Clang tells me that defining the static member outside its namespace is a C++11 extension. Better use
namespace ServiceManagement {
template <> setPosType::addFunc setPosType::s_AddFunc = 0;
}
I have a problem with the linking of a C++ project and I can't figure out what's wrong.
The jest of the code.
clitest.cpp
#include <iostream>
#include "node.h"
using namespace std;
int main(int argc, char** argv)
{
node<int> *ndNew = new node<int>(7);
return 0;
}
node.h
#ifndef NODE_H
#define NODE_H
#include <vector>
template <typename T>
class node
{
private:
node<T>* ndFather;
std::vector<node<T>* > vecSons;
public:
T* Data;
node(const T &Data);
};
#endif
node.cpp
#include "node.h"
using namespace std;
template <typename T>
node<T>::node(const T &Data)
{
this->Data = &Data;
this->ndFather = 0;
this->vecSons = (new vector<T>());
};
The compiler command that was used is
g++ -Wall -g clitest.cpp node.cpp -o clitest
The error log is goes like this
clitest.cpp: In function ‘int main(int, char**)’:
clitest.cpp:8:16: warning: unused variable ‘ndNew’ [-Wunused-variable]
node<int> *ndNew = new node<int>(7);
^
/tmp/cc258ryG.o: In function `main':
clitest.cpp:8: undefined reference to `node<int>::node(int const&)'
collect2: error: ld returned 1 exit status
make: *** [blist] Error 1
I have spent a decent amount of time shifting the code around, Trying to identify the problem and I either miss something basic, Or it's something I don't know about C++ linkage.
When using templates, the compiler needs to know how to generate the code for the class when it is instantiated. The undefined reference error is caused because the compiler did not generate the node<int>::node(int const &) constructor. See, e.g. Why can templates only be implemented in the header file?
You have a couple of options:
Put the implementation in node.h (node.cpp is removed as it not needed)
Put the implementation in a file that is #included at the bottom of node.h (usually the file would be called node.tpp)
I suggest putting the implementation in node.h and removing node.cpp. Note that the code in your example is not valid c++: the member variable vecSons is not a pointer so the line vecSons = new vector<T>() will give a compiler error. The following code could be a starting point for the full implementation:
#ifndef NODE_H
#define NODE_H
#include <vector>
template <typename T>
class node
{
private:
node<T>* ndFather;
std::vector<node<T>* > vecSons;
public:
const T* Data;
node(const T &d) :
ndFather(0),
vecSons(),
Data(&d)
{
}
};
#endif
Use -I. before the .cpp files, so that the compiler knows to look for .h files.
g++ -Wall -I. clitest.cpp node.cpp -o clitest
Or just -I:
g++ -Wall -I clitest.cpp node.cpp -o clitest
I have the following three files in the same directory:
citysim.cpp
#include "utils.h"
using namespace std;
int main()
{
City *c;
c = new City();
Graph<City *> g;
g.addVertex(c);
}
utils.h
#include <iostream>
#include <map>
#include <vector>
using namespace std;
class City {
public:
City() {}
private:
string name;
};
template <typename Tkey>
class Graph {
public:
Graph() {}
void addVertex(Tkey);
private:
vector<Tkey> v;
vector< vector<int> > e;
map<Tkey, int> key_map;
};
utils.cpp
#include "utils.h"
template <typename Tkey>
void Graph<Tkey>::addVertex(Tkey vertex)
{
v.push_back(vertex);
}
And I am really perplexed as to why the following compilation sequence produces the result indicated:
test> g++ -c citysim.cpp
test> g++ -c utils.cpp
test> g++ -o citysim citysim.o utils.o
citysim.o: In function `main':
citysim.cpp:(.text+0x4a): undefined reference to `Graph<City*>::addVertex(City*)'
collect2: ld returned 1 exit status
Any ideas or insights are appreciated!
Define everything of your templated class in your header file, not in a cpp file. Instead of having your utils.cpp have everything like this in your header file:
template <typename Tkey>
class Graph {
public:
Graph() {}
void addVertex(Tkey vertex)
{
v.push_back(vertex);
}
private:
vector<Tkey> v;
vector< vector<int> > e;
map<Tkey, int> key_map;
};
Here is the related reading in the faq...
EDIT:
(But you can define it later on like you did it in your cpp in the header file as well...)
Template functions must be written entirely on the header, their definitions can't go on the cpp file.