1

This is a simpified version of some code.

  1. The struct is defined in roughStruct.h. It has a static const char * someVar. someVar is initialized outside the struct in the same file.

  2. Another class roughParse (defined in roughParse.h and implemented in roughParse.cpp) intends to make use of roughStruct(For the purposes of this questions it does absolutely nothing)

  3. The main file roughMain.cpp intends to make use of the class roughParse to work on struct roughStruct.(Again here it does nothing.)

The code doesn't compile.

  1. As far I understand the error is occuring because roughStruct is being include in both roughMain.cpp and roughParse.cpp. I need clarification here--I am confused as to how that can be because of the next point.
  2. After a lot of trial and error, the following corrects the error:
//defining the const inline and not outside
 constexpr static const char *someVar="abcd";

or

//using constructor to initialize and not outside
roughStruct()
    {
        someVar="abcd";
    }

Both approaches don't work forconst char * replaced with const string.
Why don't they?
How do you initialize a static const string then?

The second approach doesn't seem ideal as structures are for holding data though I will use it if its the only way. But again, it doesn't solve the problem for strings.

But most importantly why do these modifications remove a linking error?

In regards to point 4, if the roughStruct was being included twice, it would still be in the above solutions as they don't change any #include directives. So point 4 is not the reason right?

Code:

The structure:

//roughStruct.h


#ifndef ROUGHSTRUCT_H
#define ROUGHSTRUCT_H

#include<string>

struct roughStruct {
    //this is the critical thing
    static const char *someVar;
//    static std::string someStringVar;
};

const char *someVar = "abcd";


#endif //ROUGHSTRUCT_H


This is the parser class:

//roughParse.h

#ifndef ROUGHPARSE_H
#define ROUGHPARSE_H

#include "roughStruct.h"

class roughParse {

    //had some code here that was implmented in roughParse.cpp
};


#endif //ROUGHPARSE_H
//roughParse.cpp

#include "roughParse.h"
#include<iostream>
using std::cout;
using std::endl;

//had some code here implementing roughParse.h

The main file:

//roughMain.cpp


#include "roughStruct.h"
#include "roughParse.h"

int main()
{
//had some code here that used roughparse and roughStruct
    return 0;
}

CMakeLists.txt:

...

add_executable(
       project
        ${SOME_DIR}roughMain.cpp
        ${SOME_DIR}roughParse.h
        ${SOME_DIR}roughParse.cpp
        ${SOME_DIR}roughStruct.h

)
...

CMake Error:

//ignore the line nos.
CMakeFiles/test/roughParse.cpp.o:project/test/roughStruct.h:13: multiple definition of `someVar'
CMakeFiles/test/roughMain.cpp.o:project/test/roughStruct.h:13: first defined here

Env
g++ (Ubuntu 7.4.0-1ubuntu1~18.04) 7.4.0
CMake: Version 3.14.3
IDE: CLion ver 2019.1.3

lineage
  • 792
  • 1
  • 8
  • 20
  • Every cpp that includes roughStruct.h will get its own `const char *someVar = "abcd";` instance. Looking for a dupe. – user4581301 May 25 '19 at 16:08
  • _"**How do you initialize a `static const string` then?**"_ Directly in the `struct` definition: `static const string someVar = "abcd";` – πάντα ῥεῖ May 25 '19 at 16:08
  • white dupe-hunting, I found this: https://stackoverflow.com/questions/2328671/constant-variables-not-working-in-header/2328715#2328715 which suggests I'm wrong. Running experiment. – user4581301 May 25 '19 at 16:12
  • @πάντα ῥεῖ tried it showed `static data member of type 'const std::string' (aka 'const basic_string') must be initialized out of line` – lineage May 25 '19 at 16:12
  • @lineage What's your compiler, which standard flags used, compiler version? – πάντα ῥεῖ May 25 '19 at 16:14
  • Related: [Initialize static variables in C++ class?](https://stackoverflow.com/questions/5019856/initialize-static-variables-in-c-class) – TrebledJ May 25 '19 at 16:14
  • Brain missed the class membership somehow. `const char *someVar = "abcd";` needs to be `const char *roughStruct ::someVar = "abcd";` or it's a new variable. Working back through the rest. – user4581301 May 25 '19 at 16:17
  • @ user4581301 thanks for your effort..though code [here](https://stackoverflow.com/questions/2328671/constant-variables-not-working-in-header/2328715#2328715) seems to talk about `extern` use for global scopped `const` vars..i am beginner a so please explain how that helps – lineage May 25 '19 at 16:26
  • @ TrebledJ moving stuff out is precisely the poblem here..i want to but it doesn't link – lineage May 25 '19 at 16:28
  • `extern` is not needed for this use case. The short answer to your question is to place `const std::string roughStruct::someStringVar="abcd";` in one and only one cpp file and NOT in a header where it can easily be duplicated. But there's some weird nuance in the question I'm still trying to work through – user4581301 May 25 '19 at 16:29
  • 1
    Do you know what C++ Standard revision you are compiling to? It's pretty important as the rules on `static` members and what can be defined inline have changed a lot over the past few years. – user4581301 May 25 '19 at 16:32
  • How far down the rabbit hole are you willing to go? Give `struct roughStruct { static constexpr std::string_view someStringVar = "abcd"; };` a try. For this you will need to have `-std=c++17` on the command line to force compiling to the most recent ratified standard. – user4581301 May 25 '19 at 16:42
  • @ user4581301 I am using CLion for learning c++..its using the g++ of the ubuntu system whose ver i have posted...the run config passes no flags/args to g++ ...CMake has the following build options `-j 4`..in all likelihood..its whatever the g++(stated ver) compiles in by default..i am guessing the core of the problem isn't that..i would like the code to wotk with at least c++11 – lineage May 25 '19 at 16:45
  • sorry..build config passes no build options to cmake – lineage May 25 '19 at 16:51
  • I don't know the default standard of g++ 7.4, unfortunately. Agree that you want at least C++11. If this is self-directed learning or you don't have a Standard to use specified by course materials, you might as well learn the most recent. That'd be C++17. Should be a configuration page in CLion that allows you to set the dialect, and if not there's be a miscellaneous options entry box somewhere. – user4581301 May 25 '19 at 16:57
  • @ user4581301 works in c++17..without it gives `error: ‘string_view’ in namespace ‘std’ does not name a type static constexpr std::string_view someStringVar = "abcd";`...whats string_view? – lineage May 25 '19 at 16:58
  • `std::string_view` ([doc link](https://en.cppreference.com/w/cpp/string/basic_string_view)) is a new addition in C++17. It gives a lightweight wrapper around something string-ish that you typically use to to look at a portion of a larger string without having to make a copy or giving a semblance of `std::string`-like behaviour to a non-`string` . But because it's so limited and simple, it can be used in ways that `std::string` cannot. Like defining inline in a class definition. – user4581301 May 25 '19 at 17:18
  • 1
    @user4581301: `const char *someVar` is not const-qualified (the pointer), so does have external linkage. – Davis Herring May 25 '19 at 20:05
  • @DavisHerring Ah-ha! That makes sense. Thank you. – user4581301 May 25 '19 at 23:55

0 Answers0