I'm trying to define a simple explicit conversion in C++11, separately from the header file, using GCC 4.8.5 (CentOS 7's default):
foo.h:
#ifndef foo_h_
#define foo_h_
typedef struct {
int x;
explicit operator int() const;
} A;
#endif
foo.cpp:
#include "foo.h"
A::operator int() const
{
return this->x;
}
main.cpp:
#include "foo.h"
int main(int,char**)
{
A a{1};
int b = (int)a - 1;
return 0;
}
GCC 4.8.5 inexplicably fails to link this code:
$ g++ -std=c++11 foo.cpp main.cpp
/tmp/cc5osctA.o: In function `main':
main.cpp:(.text+0x1e): undefined reference to `A::operator int() const'
collect2: error: ld returned 1 exit status
However, if I use any version of GCC >= 5 (e.g. GCC 5.3.1 from RHEL's devtoolset-4 software collection), it works, as I'd expect it to:
$ scl enable devtoolset-4 "g++ -std=c++11 foo.cpp main.cpp"
### (no linker errors, b == 0 when running)
Is this a bug in GCC 4.8.5's C++11 support? Or is my code malformed?
Related
I'm new to C++17. Considering the following code:
// ---------------
// in MyClass.hpp
// ---------------
#pragma once
class MyClass {
public:
static const int A;
};
inline const int MyClass::A = 100;
// ---------------
// in test.cpp
// ---------------
#include <stdio.h>
#include "MyClass.hpp"
void test() {
printf("test: %p\n", &MyClass::A);
}
// ---------------
// in main.cpp
// ---------------
#include <stdio.h>
#include "MyClass.hpp"
extern void test();
int main() {
printf("main: %p\n", &MyClass::A);
test();
}
When compiled with MinGW-W64 g++ 8.1.0
g++ -std=c++17 main.cpp test.cpp -o test.exe
The output is
main: 00000000004044B0
test: 00000000004044B0
which works as expected.
However, in MSVC 2017
cl /std:c++17 main.cpp test.cpp
I got a compiler error, saying redefinition of "public: static int const MyClass::A". (Sorry, the compiler output contains Chinese characters. It's not appropriate to post here directly.)
Why the code works under g++, but fails in MSVC? Did I do something wrong?
I can confirm that Clang accepts your code without any warning.
What worries me is that cppreference shows the following note:
The inline specifier cannot re-declare a function or variable (since C++17) that was already defined in the translation unit as non-inline.
I could not really identify the real cause for that note in C++ standard. But as cppreference is generally correct in its warnings, I assume that it is the reason why MSVC chokes on your code. It would probably expect:
// ---------------
// in MyClass.hpp
// ---------------
#pragma once
class MyClass {
public:
static const int A = 100;
};
in order to avoid a former non inline declaration followed with an inline definition.
i have this simple code in the following files:
Stat.h
#ifndef STAT_H
#define STAT_H
class Stat {
public:
void compute_value();
};
#endif
Stat.cpp
class Stat {
public:
void compute_value() {
}
};
main.cpp
#include "Stat.h"
int main(void)
{
Stat stat;
stat.compute_value();
}
When i try to compile i got the following error:
clang++ -std=c++14 -Wall -Wextra -pedantic -Weverything -O3 Stat.cpp main.cpp -o main
/tmp/main-0466d7.o: In function `main':
main.cpp:(.text+0xf6a): undefined reference to `Stat::compute_value()'
clang: error: linker command failed with exit code 1 (use -v to see invocation)
You are redefining the class in your Stat.cpp source file because definition is also a declaration. Instead of having the entire class redefinition you only need to define the member function(s) in your Stat.cpp source file and include the Stat.h header:
#include "Stat.h"
void Stat::compute_value() {}
I am trying to get a template code working with the header file and cpp file separated. I use explicit instantiation for this. But I still get an undefined reference error.
foo.h
template<typename T>
class Foo
{
public:
void f();
};
foo.cc
#include <iostream>
#include "Foo.h"
template<typename T>
void Foo<T>::f()
{
std::cout << "Foo<T>::f()\n";
}
template class Foo<int>;
main.cc
#include "foo.h"
int main()
{
Foo<int> x;
x.f();
}
When I compile:
g++ main.cc -o test
/tmp/ccfHjiVJ.o: In function `main':
main.cc:(.text+0x10): undefined reference to `Foo<int>::f()'
collect2: ld returned 1 exit status
The gcc version I use is gcc version 4.4.7 20120313 (Red Hat 4.4.7-4) (GCC)
You've forgotten to compile foo.cc in your compile command, add foo.cc:
g++ main.cc foo.cc -o test
^^^^^^
I am trying to compile C++ code with Geany.
Compile command: g++ -Wall -c "%f"
Build command: g++ -Wall -o "%e" "%f"
main.cpp:
#include <iostream>
#include "Person.hpp"
int main()
{
Person p1(16);
std::cout << p1.getAge();
return 0;
}
Person.hpp
class Person
{
public:
Person(int a);
void setAge(int);
int getAge() const;
private:
int age;
};
inline int Person::getAge() const
{
return age;
}
Person.cpp
#include "Person.hpp"
Person::Person(int a)
{
age = a;
}
void Person::setAge(int a)
{
age = a;
}
Error:
g++ -Wall -o "main" "main.cpp" (in directory:
/home/me/projects/Test) /tmp/ccxYmWkE.o: In function main':
main.cpp:(.text+0x15): undefined reference toPerson::Person(int)'
collect2: error: ld returned 1 exit status Compilation failed.
Before Geany, I only used Code::Blocks and everything worked fine. How can I fix it?
It's obvious you didn't add Person.cpp to the compilation command. then it can not pass the linkage level.
Add -o Person Person.cpp to the build option after g++ -Wall -c "%e" "%f".
After all the compile command should be something like below:
g++ -Wall -o "main" "main.cpp" -o Person Person.cpp
class.h
#include <iostream>
#include <stdint.h>
using namespace std;
template <typename T>
class CIntegerType {
public:
void Show ( void );
private:
T m_Data;
};
class.cpp
#include "class.h"
template <typename T>
void CIntegerType<T> :: Show ( void ) {
cout << m_Data << endl;
}
main.cpp
#include "class.h"
int main ( void ) {
CIntegerType<uint32_t> UINT32;
UINT32 . Show ();
return 0;
}
This commands return:
g++ -Wall -pedantic -c main.cpp
g++ -Wall -pedantic -c class.cpp
g++ -Wall -pedantic -o class.o main.o
main.o: In function `main':
main.cpp:(.text+0x11): undefined reference to 'CIntegerType< unsigned int>::Show()'
collect2: ld returned 1 exit status
Try putting your template implementation in the header file.
See: Why can templates only be implemented in the header file?
Try g++ -Wall -pedantic -o main.o class.o instead. You are facing the same problem as in this question: g++ linking order dependency when linking c code to c++ code
The linker searches for functions in the order they appear. Since you have a template function, its use in main must be fed to the linker prior to the actual code to instantiate it in class.