I am trying to write logger.
This is my header file with logger
#include <iostream>
void logInfo(){}
void logWarning(){}
void logError(){}
void logDebug(){}
template<typename First, typename ...Rest>
void logInfo(First && first, Rest && ...rest)
{
std::cout << "[INFO] " << std::forward<First>(first) << std::endl;
logInfo(std::forward<Rest>(rest)...);
}
template<typename First, typename ...Rest>
void logWarning(First && first, Rest && ...rest)
{
std::cout << "[WARNING] " << std::forward<First>(first) << std::endl;
logWarning(std::forward<Rest>(rest)...);
}
template<typename First, typename ...Rest>
void logError(First && first, Rest && ...rest)
{
std::cout << "[ERROR] " << std::forward<First>(first) << std::endl;
logError(std::forward<Rest>(rest)...);
}
template<typename First, typename ...Rest>
void logDebug(First && first, Rest && ...rest)
{
std::cout << "[DEBUG] " << std::forward<First>(first) << std::endl;
logDebug(std::forward<Rest>(rest)...);
}
Then if I will include this logger to main it is working okay:
#include "CLogger.hpp"
using namespace std;
int main()
{
logInfo("something");
}
But if I'm trying to include logger in other class:
#include <iostream>
#include "CFileManager.hpp"
#include "CLogger.hpp"
const char* CFileManager::PWD_COMMAND = "PWD";
const std::string CFileManager::DATA_FILE_NAME = "/data.txt";
CFileManager::CFileManager()
: mFile()
, mPathToFile( getenv( PWD_COMMAND ) )
{
mFile = std::ofstream{ mPathToFile + DATA_FILE_NAME };
}
CFileManager::~CFileManager()
{
mFile.close();
}
Binary doesn't compile. This is error:
/usr/bin/ld: CFileManager.o: in function `logInfo()':
CFileManager.cpp:(.text+0x0): multiple definition of `logInfo()'; main.o:main.cpp:(.text+0x0): first defined here
/usr/bin/ld: CFileManager.o: in function `logWarning()':
CFileManager.cpp:(.text+0xb): multiple definition of `logWarning()'; main.o:main.cpp:(.text+0xb): first defined here
/usr/bin/ld: CFileManager.o: in function `logError()':
CFileManager.cpp:(.text+0x16): multiple definition of `logError()'; main.o:main.cpp:(.text+0x16): first defined here
/usr/bin/ld: CFileManager.o: in function `logDebug()':
CFileManager.cpp:(.text+0x21): multiple definition of `logDebug()'; main.o:main.cpp:(.text+0x21): first defined here
It could be the case, that I missing something in makefile?:
#folders
IMPL_DIR := src
HEADER_DIR := include
BIN_DIR := bin
#flags
CCFLAGS := -Wall -Wextra -pedantic -std=c++17
IINCLUDE := -I$(HEADER_DIR)
#output
output: main.o CFileManager.o
g++ $(CCFLAGS) $(IINCLUDE) main.o CFileManager.o -o $(BIN_DIR)/login
#main
main.o: main.cpp | $(BIN_DIR)
g++ $(IINCLUDE) -c main.cpp
#fileManager
CFileManager.o: $(HEADER_DIR)/CFileManager.hpp $(IMPL_DIR)/CFileManager.cpp
g++ $(IINCLUDE) -c $(IMPL_DIR)/CFileManager.cpp
#create bin folder
$(BIN_DIR):
mkdir -p $#
#make clean
.PHONY: clean
clean:
$(RM) *.o
Because I doesn't change anything in makefile, because this is only header.
What's wrong?
UPDATE
Did you know how could I add more information to the log?
I want to see:
FILE_NAME - Name of the file where log was used
FUNCTION - Function name where log was used
LINE - Line in which log was used
Can I somehow modify my code easily? Or should I re implement completely?
void logInfo(){}
void logWarning(){}
void logError(){}
void logDebug(){}
Are regular functions, so if included in different translation unit, you have multiple definitions.
Marking them inline would solve the issue:
inline void logInfo(){}
inline void logWarning(){}
inline void logError(){}
inline void logDebug(){}
For your specific case, you might rewrite your template method to avoid the need of those methods BTW:
template<typename... Ts>
void logInfo(Ts&&...args)
{
((std::cout << "[INFO] " << std::forward<Ts>(args) << std::endl), ...);
}
Related
… or is it enough to declare them at the module interface unit?
test.cpp:
module;
#include <iostream>
export module M;
export
template<typename>
class T
{
public:
void foo() const
{ std::cout << "T" << std::endl; }
};
// export <-- NOT exported
template<>
class T<int>
{
public:
void foo() const
{ std::cout << "T<int>" << std::endl; }
};
main.cpp:
import M;
int main()
{
T<int> x;
x.foo();
return 0;
}
Output:
$ rm -f gcm.cache/* && $(HOME)/gcc-master/bin/g++ -O3 -fmodules-ts test.cpp main.cpp -o foo && ./foo
T<int>
$ $(HOME)/gcc-master/bin/g++ --version
g++ (GCC) 11.0.0 20210128 (experimental)
Exporting affects only name lookup and linkage. Neither of those is relevant to any kind of template specialization or instantiation, so they never need exporting.
This question already has answers here:
Why full specialization of template function is not picked up from the .cpp file without declaration?
(3 answers)
Closed 4 years ago.
Here's my program:
print.hpp:
#pragma once
#include <iostream>
template<size_t p>
void print()
{
std::cout << "" << __FILE__ << "" << __LINE__ << "" << std::endl;
exit(0);
}
print.cpp:
#include "print.hpp"
template<>
void print<13>()
{
std::cout << "Unlucky." << std::endl;
}
main.cpp:
#include <iostream>
#include "print.hpp"
int main()
{
std::cout << "Started." << std::endl;
print<13>();
std::cout << "Exiting." << std::endl;
}
When I compile that with g++ main.cpp print.cpp -O0 -std=c++11 && ./a.out it works fine (output is:
Started.
Unlucky.
Exiting.
).
However, if'd I compile that with g++ main.cpp print.cpp -O1 -std=c++11 && ./a.out it would give me a segmentation fault with the output:
Started.
Unlucky.
Speicherzugriffsfehler //German for memory access error
Almost the same with clang++, without optimization it would do its job just fine
and with -O1 or higher it outputs that:
Started.
Unlucky.
./print.hpp8
Why is that?
You need to declare the template specialization in the .hpp file.
template<size_t p>
void print()
{
std::cout << "" << __FILE__ << "" << __LINE__ << "" << std::endl;
exit(0);
}
// Declare the specialization.
template<> void print<13>();
Without the declaration in the .hpp file, I get a linker error with g++ 6.4.0.
.../Local/Temp/cctCC5MK.o:print.cc:(.text+0x0): multiple definition of `void print<13ul>()'
.../Local/Temp/ccgodRUG.o:socc.cc:(.text$_Z5printILm13EEvv[_Z5printILm13EEvv]+0x0): first defined here
collect2: error: ld returned 1 exit status
I am not sure how you are able to successfully build your program without the declaration.
Using g++, when two compilation units "a1.o" and "a2.o" both define and use the same weak symbol, the linker will silently resolve to the first occurrence of the symbol wherever it is used. As a result, the behavior of the application will depend on the order of the object files on the linker command line. What can be done to ensure that these symbols are resolved locally to each compilation unit?
For instance, as a minimalist example, if I have the following source files:
a1.cpp:
#include <iostream>
struct A
{
void foo() {std::cerr << __FILE__ << std::endl;}
};
void bar1() {A a; a.foo();}
a2.cpp:
#include <iostream>
struct A
{
void foo() {std::cerr << __FILE__ << std::endl;}
};
void bar2() {A a; a.foo();}
main.cpp:
void bar1();
void bar2();
int main()
{
bar1();
bar2();
}
and compile them with:
for i in a1 a2 main ; do g++ -c -o $i.o $i.cpp ; done
The output will depend on the relative position of a1.o and a2.o on the linker command line:
g++ -o main main.o a{1,2}.o ; ./main
a1.cpp
a1.cpp
g++ -o main main.o a{2,1}.o ; ./main
a2.cpp
a2.cpp
I'd like to get the same result as if using the '-fno-weak' command line option:
for i in a1 a2 main ; do g++ -fno-weak -c -o $i.o $i.cpp ; done
g++ -o main main.o a{1,2}.o ; ./main
a1.cpp
a2.cpp
but '-fno-weak' seems to lead to other complications. What are the alternatives (besides not inlining and fixing collisions)?
For those wondering what could be a typical use case: when writing mock components it is sometimes convenient to have header-only implementations. Different test fixtures end-up having different mock implementations of the same component type, which becomes an issue when all the fixtures are linked into a single test runner.
You asked:
What are the alternatives (besides not inlining and fixing collisions)?
Use local namespaces or anonymous namespaces.
a1.cpp:
#include <iostream>
namespace A1_namespace
{
struct A
{
void foo() {std::cerr << __FILE__ << std::endl;}
};
}
using namespace A1_namespace;
void bar1() {A a; a.foo();}
or
#include <iostream>
namespace
{
struct A
{
void foo() {std::cerr << __FILE__ << std::endl;}
};
}
void bar1() {A a; a.foo();}
Make similar changes to a2.cpp.
I'm unable to figure out what's the problem here. I have a ConsoleIO class, which contains two methods:
static void OutputMessage(const std::string &message);
static void OutputMessageNoNewLine(const std::string &message);
They are defined inline in the header:
inline void ConsoleIO::OutputMessage(const std::string &message)
{
std::cout << message << std::endl;
}
inline void OutputMessageNoNewLine(const std::string &message)
{
std::cout << message << " ";
std::flush(std::cout);
}
Also another class, ContentParser, with the methods:
static const bool StringEquals(const char *a, const char *b);
template <typename T>
static const std::string NumToString(const T num);
template <typename T>
static const T StringToNum(const std::string &s);
Which are defined in a separate file, ContentParser.cpp.
template <typename T>
const std::string ContentParser::NumToString(const T num)
{
std::ostringstream ss;
ss << num;
return ss.str();
}
I have the following code in the AdventureGame class:
ConsoleIO::OutputMessageNoNewLine(ContentParser::NumToString(num+1));
ConsoleIO::OutputMessage(" - " + decision.choices.at(num).text);
The strange thing is, from the above, the bottom line works fine, but the top produces an error when linking (line 65 error). The StringEquals method also works everywhere.
Here is the build log:
14:03:02 **** Incremental Build of configuration Debug for project AdventureGame ****
Info: Internal Builder is used for build
g++ -O0 -g3 -Wall -c -fmessage-length=0 -std=c++11 -o AdventureGame.o "..\\AdventureGame.cpp"
g++ "-LD:\\Program Files\\tinyxml2-master" -o AdventureGame.exe tinyxml2.o Main.o ContentParser.o AdventureGame.o -ltinyxml
AdventureGame.o: In function `AdventureGame::ProcessDecision()':
D:\adat\eclipse\AdventureGame\Debug/../AdventureGame.cpp:65: undefined reference to `std::string const ContentParser::NumToString<unsigned int>(unsigned int)'
D:\adat\eclipse\AdventureGame\Debug/../AdventureGame.cpp:65: undefined reference to `ConsoleIO::OutputMessageNoNewLine(std::string const&)'
D:\adat\eclipse\AdventureGame\Debug/../AdventureGame.cpp:68: undefined reference to `ConsoleIO::OutputMessageNoNewLine(std::string const&)'
collect2.exe: error: ld returned 1 exit status
What am I missing?
This
inline void OutputMessageNoNewLine(const std::string &message)
{
std::cout << message << " ";
std::flush(std::cout);
}
should be this
inline void ConsoleIO::OutputMessageNoNewLine(const std::string &message)
{
std::cout << message << " ";
std::flush(std::cout);
}
Easy mistake to make.
Is it possible to have a unique address allocated for a constexpr variable, i.e. the same for all translation units where the variable is available (usually through a header)? Consider the following example:
// foo.hh
#include <iostream>
constexpr int foo = 42;
// a.cc
#include "foo.hh"
void a(void) { std::cout << "a: " << &foo << std::endl; }
// b.cc
#include "foo.hh"
extern void a(void);
int main(int argc, char** argv) {
a();
std::cout << "b: " << &foo << std::endl;
}
Compiling a.cc and b.cc separately, and linking them together using gcc 4.7, I see two different addresses printed. If I add the keyword extern in the header, I get a linker error duplicate symbol _foo in: a.o and b.o which I find kind of surprising, because I thought that adding extern would more likely cause the compiler to import that symbol from another object instead of exporting it from the current object. But it seems my understanding of how things work was wrong here.
Is there a reasonable way to have a constexpr declared in one header, such that all translation units can use it in their constant expressions, and such that all translation units agree as to the address of that symbol? I would expect some additional code to denote the single translation unit where this symbol actually belongs to, just like with extern and non-extern variables without constexpr.
If you need to take the address of constexpr variable, declare it as a static member variable. It can be used as a constant expression this way (as opposed to using a function returning a const).
foo.h:
#ifndef FOO_H
#define FOO_H
struct Foo {
static constexpr int foo { 42 }; // declaration
};
#endif // FOO_H
foo.cpp:
#include "foo.hpp"
constexpr int Foo::foo; // definition
bar.cpp:
#include "foo.hpp"
const int* foo_addr() {
return &Foo::foo;
}
int foo_val() {
return Foo::foo;
}
main.cpp:
#include <iostream>
#include "foo.hpp"
extern const int* foo_addr();
extern int foo_val();
constexpr int arr[Foo::foo] {}; // foo used as constant expression
int main() {
std::cout << foo_addr() << " = " << foo_val() << std::endl;
std::cout << &Foo::foo << " = " << Foo::foo << std::endl;
}
Output:
$ g++ -std=c++11 foo.cpp bar.cpp main.cpp -o test && ./test
0x400a44 = 42
0x400a44 = 42
C++17 inline variables
This awesome C++17 feature allow us to:
conveniently use just a single memory address for each constant
store it as a constexpr: How to declare constexpr extern?
do it in a single line from one header
main.cpp
#include <cassert>
#include "notmain.hpp"
int main() {
// Both files see the same memory address.
assert(¬main_i == notmain_func());
assert(notmain_i == 42);
}
notmain.hpp
#ifndef NOTMAIN_HPP
#define NOTMAIN_HPP
inline constexpr int notmain_i = 42;
const int* notmain_func();
#endif
notmain.cpp
#include "notmain.hpp"
const int* notmain_func() {
return ¬main_i;
}
Compile and run:
Compile and run:
g++ -c -o notmain.o -std=c++17 -Wall -Wextra -pedantic notmain.cpp
g++ -c -o main.o -std=c++17 -Wall -Wextra -pedantic main.cpp
g++ -o main -std=c++17 -Wall -Wextra -pedantic main.o notmain.o
./main
GitHub upstream.
See also: How do inline variables work?
C++ standard on inline variables
The C++ standard guarantees that the addresses will be the same. C++17 N4659 standard draft
10.1.6 "The inline specifier":
6 An inline function or variable with external linkage shall have the same address in all translation units.
cppreference https://en.cppreference.com/w/cpp/language/inline explains that if static is not given, then it has external linkage.
Inline variable implementation
We can observe how it is implemented with:
nm main.o notmain.o
which contains:
main.o:
U _GLOBAL_OFFSET_TABLE_
U _Z12notmain_funcv
0000000000000028 r _ZZ4mainE19__PRETTY_FUNCTION__
U __assert_fail
0000000000000000 T main
0000000000000000 u notmain_i
notmain.o:
0000000000000000 T _Z12notmain_funcv
0000000000000000 u notmain_i
and man nm says about u:
"u" The symbol is a unique global symbol. This is a GNU extension to the standard set of ELF symbol bindings. For such a symbol the dynamic linker will make sure that in the entire process
there is just one symbol with this name and type in use.
so we see that there is a dedicated ELF extension for this.
I think constexpr is meant more for functions whose return value is constant. You can bind a constant variable to the return value of a constexpr function and expose that externally instead. For example:
// constexpr.h
#ifndef __CONSTEXPR_H
#define __CONSTEXPR_H
extern const int foo;
#endif // __CONSTEXPR_H
// constexpr.cpp
#include "constexpr.h"
constexpr int foo_expr()
{
return 42;
}
const int foo = foo_expr();
// unit1.cpp
#include <iostream>
#include "constexpr.h"
void unit1_print_foo()
{
std::cout << &foo << " = " << foo << std::endl;
}
// unit2.cpp
#include <iostream>
#include "constexpr.h"
void unit2_print_foo()
{
std::cout << &foo << " = " << foo << std::endl;
}
// main.cpp
extern void unit1_print_foo();
extern void unit2_print_foo();
int main(int, char**)
{
unit1_print_foo();
unit2_print_foo();
}
My result is:
$ g++-4.7 -std=c++11 constexpr.cpp unit1.cpp unit2.cpp main.cpp -o test && ./test
0x400ae4 = 42
0x400ae4 = 42
However, it should usually be sufficient to make the foo_expr function itself externally visible, and callers would use foo_expr() to get the value instead of treating it like a variable.