JSON C++

Using Visual C++ 2022 community edition to compile following JSON C++ program from
book C++20 for Programmers by Deitel & Deitel, Published in 2022,
chapter 9 page 331.

This program uses JSON cereal library from
https://uscilab.github.io/cereal/index.html

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
// fig09_36.cpp
// Serializing and deserializing objects with the cereal library.
#include "cereal/archives/json.hpp"
#include "cereal/types/vector.hpp"  
#include "fmt/format.h"

#include <fstream>
#include <iostream>
#include <vector>

struct Record {
   int account{};
   std::string first{};
   std::string last{};
   double balance{};
};

// function template serialize is responsible for serializing and 
// deserializing Record objects to/from the specified Archive
template <typename Archive>
void serialize(Archive& archive, Record& record) {
   archive(cereal::make_nvp("account", record.account),
      cereal::make_nvp("first", record.first),
      cereal::make_nvp("last", record.last),
      cereal::make_nvp("balance", record.balance));
}

// display record at command line
void displayRecords(const std::vector<Record>& records) {
   for (const auto& r : records) {
      std::cout << fmt::format("{} {} {} {:.2f}\n",
         r.account, r.first, r.last, r.balance);
   }
}

int main() {
   std::vector records{
      Record{100, "Brian", "Blue", 123.45},
      Record{200, "Sue", "Green", 987.65}
   };

   std::cout << "Records to serialize:\n";
   displayRecords(records);

   // serialize vector of Records to JSON and store in text file
   if (std::ofstream output{"records.json"}) {
      cereal::JSONOutputArchive archive{output};
      archive(cereal::make_nvp("records", records)); // serialize records
   }

   // deserialize JSON from text file into vector of Records
   if (std::ifstream input{"records.json"}) {
      cereal::JSONInputArchive archive{input};
      std::vector<Record> deserializedRecords{};
      archive(deserializedRecords); // deserialize records
      std::cout << "\nDeserialized records:\n";
      displayRecords(deserializedRecords);
   }
}


This program is giving link errors.

How to fix these errors please?

I am not able to copy and paste the errors from Visual C++ 2022 to this Window.

I am getting errors E2500, LINK2019 and LINK1120 unresolved externals.




Last edited on
Without knowing the errors we can't really tell anything about the problems...

Did you try to compile the examples they provide?
In that example serialize(...) is a member of the record:
1
2
3
4
5
6
7
8
9
10
11
struct MyRecord
{
  uint8_t x, y;
  float z;
  
  template <class Archive>
  void serialize( Archive & ar )
  {
    ar( x, y, z );
  }
};
I am not able to copy and paste the errors from Visual C++ 2022 to this Window.


Why not - I can?

What is the name(s) referred to in the link error for unresolved external?

PS You haven't got:

 
#include <string> 

Last edited on
For VS2022, this compiles and runs OK (assuming that you have set 'Additional Include Directories' to point to where cereal/include directory is located on your system. Also note that for VS2022 you don't need to use the 3rd party fmt library as VS2022 supports std::format (which might be the source of the issue).

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
#include <fstream>
#include <iostream>
#include <vector>
#include <format>
#include <string>

#pragma warning( disable : 5054)          // operator 'operator-name': deprecated between enumerations of different types
#include "cereal\\archives\\json.hpp"
#include "cereal\\types\\vector.hpp"

struct Record {
	int account {};
	std::string first {};
	std::string last {};
	double balance {};
};

// function template serialize is responsible for serializing and
// deserializing Record objects to/from the specified Archive
template <typename Archive>
void serialize(Archive& archive, Record& record) {
	archive(cereal::make_nvp("account", record.account),
		cereal::make_nvp("first", record.first),
		cereal::make_nvp("last", record.last),
		cereal::make_nvp("balance", record.balance));
}

// display record at command line
void displayRecords(const std::vector<Record>& records) {
	for (const auto& r : records) {
		std::cout << std::format("{} {} {} {:.2f}\n",
			r.account, r.first, r.last, r.balance);
	}
}

int main() {
	std::vector records {
	   Record{100, "Brian", "Blue", 123.45},
	   Record{200, "Sue", "Green", 987.65}
	};

	std::cout << "Records to serialize:\n";
	displayRecords(records);

	// serialize vector of Records to JSON and store in text file
	if (std::ofstream output { "records.json" }) {
		cereal::JSONOutputArchive archive { output };
		archive(cereal::make_nvp("records", records)); // serialize records
	}

	// deserialize JSON from text file into vector of Records
	if (std::ifstream input { "records.json" }) {
		cereal::JSONInputArchive archive { input };
		std::vector<Record> deserializedRecords {};
		archive(deserializedRecords); // deserialize records
		std::cout << "\nDeserialized records:\n";
		displayRecords(deserializedRecords);
	}
}


Note L7 is needed to remove the warnings generated by the old cereal code.


Records to serialize:
100 Brian Blue 123.45
200 Sue Green 987.65

Deserialized records:
100 Brian Blue 123.45
200 Sue Green 987.65

Last edited on
am getting errors E2500, LINK2019 and LINK1120 unresolved externals.

Just giving us error numbers without even a hint of what the errors are isn't all that helpful. What isn't being properly linked?

Highlight the error(s) in the output window, right click and select "copy." Now you have the exact wording of the error(s) in the copy buffer ready for pasting.

You're using at least 2 different 3rd party libraries, {fmt} and cereal. {fmt} isn't a header-only library, to use it requires library files be created before use. You have to compile the library.

Not adding library and header directories to the project can be a major source of linker errors.

Microsoft has created a package manager, vcpkg, for adding available 3rd party libraries very easy. {fmt} and cereal are both available packages with vcpkg.

https://vcpkg.io/en/index.html
https://vcpkg.io/en/getting-started.html

One nice feature of vcpkg is the ability of integrating into Visual Studio. With that integration there is no need to manually add header/library directories. With a couple of console mode commands a package is downloaded, compiled as needed, and VS is able to access the libs and headers as if they were native VS libs and headers.

It is also possible to install a particular library for x64 and x86 use, as well as x64-static (no external DLL needed).

When a library gets an update, and that update is added to the vcpkg update list, vcpkg does all work with updating the package as well and any other installed package that depends on it.

If'n someone has {fmt} installed via vcpkg, for example, any #includes/imports use angle brackets < > instead of " ".

There are over 1,500 libraries maintained in vcpkg, there is little reason to not use it. The ease of maintaining 3rd party libraries with vcpkg is almost a no-brainer.
Here's my vcpkg command to install the cereal library:

vcpkg install cereal:x86-windows cereal:x64-windows cereal:x64-windows-static >>install.txt

It installs 3 versions of the library for Windows/VS and the output from the install is appended to the end of a text file so I can keep a record of what gets installed.

If I had any already installed libraries that had interlocked dependencies all the affected libraries would have been updated, not just cereal.

I have {fmt} installed since there are a couple of features it has that <format> doesn't have. At least not yet.

fmt::print is one.
https://fmt.dev/latest/index.html
With vcpkg installed {fmt} and cereal the original source code compiles without an error with Visual Studio 2022 17.3.4.

Whether the code actually works as intended when run, I can't say.

Changing the #include "" to #include <> wasn't required, I still did it. With vcpkg installed libraries VS can now autocomplete when typing multiple nested headers in 3rd party libraries.

Maybe, AlexCantor, you should consider mucking around with vcpkg. :)
Here's the "Build Solution" output from the original source code:

Build started...
1>------ Build started: Project: Project1, Configuration: Debug x64 ------
1>Scanning sources for module dependencies...
1>Source.cpp
1>Compiling...
1>Source.cpp
1>   Creating library C:\Programming\My Projects\Project1\x64\Debug\Project1.lib and object C:\Programming\My Projects\Project1\x64\Debug\Project1.exp
1>Project1.vcxproj -> C:\Programming\My Projects\Project1\x64\Debug\Project1.exe
========== Build: 1 succeeded, 0 failed, 0 up-to-date, 0 skipped ==========

I highlighted the text in the output window, right clicked and selected copy.

So, yeah, you can copy'n'paste error output as well. :)
This program uses JSON cereal library from

I'm going to go a bit pedantic here and mention cereal is a 3rd party library for serializing data that can use JSON as one possible encoding. Data can be encoded as XML or binary data as well according to the cereal documentation.

There are other libraries available that do serialization, Boost is one.
https://www.boost.org/doc/libs/1_80_0/libs/serialization/doc/index.html
Hello Seeplus:
Many, many thanks for fixing the program by correcting include paths, pragma warnings disable, etc.

My Visual C++ 2022 project is now building & running without errors.
Again, thanks a bunch.


Hello, GeorgeP, Coder777 and all others:

I can never be able to say enough thanks for your excellent, pretty fast help.

Again, thanks and best regards to all of you for your precious time.

I am marking this topic as solved. Thaaaanks.


Topic archived. No new replies allowed.