1

Using C++14, I'm trying to define a variable in a namespace where commonly used variables are stored (App::Common). The main function should be the one that sets it, since it gets set to argv[0]. Meanwhile I need the variable to be visible by all other classes/files. But I get the linker error shown below. Also, ideally I would like the variable to be const where only the main function would set it once.

common.hpp

#pragma once #include <string> namespace App{ namespace Common{ extern std::string appPath; } } 

main.cpp

#include "common.hpp" #include "client.hpp" #include <string> int main() { App::Common::appPath = argv[0]; } 

client.hpp

#include "common.hpp" class Client { public: void printAppPath(); }; 

client.cpp

#include <iostream> #include <string> #include "common.hpp" #include "client.hpp" void Client::printAppPath() { std::cout << App::Common::appPath << std::endl; } 

I get the following error by the linker:

ld: main.o: in function `main': main.cpp:(.text.startup.main+0x25): undefined reference to `App::Common::appPath[abi:cxx11]' ld: Client.o: in function `Client::printAppPath()': Client.cpp:(.text...): undefined reference to `App::Common::appPath[abi:cxx11]' 
4
  • No, because in that post, there were no definitions. My problem is that there are definitions just either not visible, or considered multiple definitions. Commented Dec 27, 2019 at 9:17
  • It is exactly same and all the same old boooring answers. Commented Dec 27, 2019 at 9:21
  • If it's the same, can you explain what changes can I do to my code. As I don't see it related. Thanks for your help. Commented Dec 27, 2019 at 9:25
  • You have 2 answers answering it in exactly same way and you are arguing with those answers already so it is hard to imagine in where your confusion lies. Commented Dec 27, 2019 at 9:27

3 Answers 3

2

This

#pragma once #include <string> namespace App{ namespace Common{ extern std::string appPath; } } 

contains only declaration of the variable appPath without its definition.

Here

#include "common.hpp" #include "client.hpp" #include <string> int main() { App::Common::appPath = argv[0]; } 

there is used the assignment operator to assign a value tp the variable appPath as if it were already defined. However actually its definition does not yet exist.

You can define the variable in any module in any enclosing namespace of the namespace Common or inside the namespace. For example you could define it in client.cpp like

std::string App::Common::appPth; 
Sign up to request clarification or add additional context in comments.

3 Comments

I do not want to define it in client.cpp. I want the main function to define it, and the client to use that definition. Anyway, I tried this in main.cpp: std::string App::Common::appPath{argv[0]}; But now I get: main.cpp: In function 'int main(int, const char**)': main.cpp: error: qualified-id in declaration before '{' token std::string App::Common::appPath{argv[0]};
@AK Either the variable is defined in a namespace or declared and defined in a block scope. You may not define a variable declared in a namespace in a block scope.
@AK You're confusing definition and assignment.
2

You are mixing definition and assignment, which are two different things for a variable:

  • a declaration for a variable x tells your compiler that there exists somewhere a variable named x;
  • a definition for a variable x tells your compiler that it needs to reserve some space for this variable x, and that the variable x will live at this location;
  • an assignment assigns a value to a variable.

For a variable, a declaration is usually a definition:

void foo() { int a; // Declaration AND Definition! } 

...except when the variable is marked as extern, since extern explicitly tells the compiler that this variable is defined elsewhere. In your case, this:

namespace App::Common { // C++17 style extern std::string appPath; } 

...is a declaration, but this:

namespace App::Common { // C++17 style std::string appPath; } 

...would be a definition (and also a declaration), and this:

int main(int argc, char *argv[]) { App::Common::appPath = std::string(argv[0]); } 

...is an assignment.

You should not define appPath in a header such as common.hpp, otherwize, you will have multiple definitions of the same variable (one for each .cpp file that includes your common.hpp) and the program will fail to compile.

What you want is a single definition for your program, and the only way to obtain it is to define App::Common::appPath once-and-for-all in a .cpp file. You can define it in main.cpp if you want:

#include <string> #include "common.hpp" #include "client.hpp" // Definition: std::string App::Common::appPath; int main() { // Assignment: App::Common::appPath = argv[0]; } 

Comments

1

You need definition:

in Common.cpp:

namespace App{ namespace Common{ std::string appPath; } } 

4 Comments

With definition, I get this error: ld: ./Client.o:(.bss._ZN4pkgr6common8pkgrPathB5cxx11E+0x0): multiple definition of App::Common::appPath[abi:cxx11]'; main.o:(.bss...): first defined here
You need only one definition in a cpp, don't place it in several cpp. and don't put it in header neither.
Yes, that's why in the OP code, I had extern. And only the main function did the definition. Can you elaborate?
Your main doesn't define it, but only assign a value to it.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.