Home > Software engineering >  C How to correctly print value of templated type from module
C How to correctly print value of templated type from module

Time:09-22

I have a vector class inside a module:

// other_library.cpp
module;
#include <iostream>

export module mylibrary.other;

export template<class T> class Vector
{
private:
    T x, y;

public:
    Vector(T _x, T _y) : x(_x), y(_y) {}

    void Write()
    {
        std::cout << "Vector{" << x << ", " << y << "}\n";
    }
};

And inside main, I create a vector and print its contents:

// main.cpp
import mylibrary.other;

int main()
{
    Vector<int> vec(1, 2);
    vec.Write();

    return 0;
}

However, I get the unexpected print to terminal: Vector{10x55a62f2f100c20x55a62f2f100f

These are the build commands used:

g  -11 -std=c  20 -fmodules-ts -c other_library.cpp
g  -11 -std=c  20 -fmodules-ts -c main.cpp
g  -11 -std=c  20 -fmodules-ts *.o -o app
./app

Naturally, if I move the vector class to the main file the print works as expected. I know that module support is still somewhat experimental. But I would expect something simple like this to just work. But perhaps I'm doing something wrong?

EDIT:

A kind-of broken hack is to manually include iostream at the top of the main file, before importing the module, like this:

// main.cpp
#include <iostream>
import mylibrary.other;

int main()
{
    Vector<int> vec(1, 2);
    vec.Write();

    return 0;
}

This will correctly print the contents of the Vector. But why is this necessary? The point of putting stuff in module is to avoid the trouble of header-inclusion.

Thus, my question is now two-fold.

CodePudding user response:

So it seems that there are still some challenges with modules. Example: I cannot use std::endl inside the Vector.Write member function.

A solution is to precompile the iostream standard header, which can be done like this:

g  -11 -std=c  20 -fmodules-ts -xc  -system-header iostream

The precompiled module will be stored in the gcm.cached/ directory, and will be an implicit search path for consecutive gcc-commands.

Now, I can completely avoid including the standard header, so the library file will look like this now:

// other_library.cpp
export module mylibrary.other;
import <iostream>;

export template<class T> class Vector
{
private:
    T x, y;

public:
    Vector(T _x, T _y) : x(_x), y(_y) {}

    void Write()
    {
        std::cout << "Vector{" << x << ", " << y << "}"
                  << std::endl;
    }
};

And I don't need to do anything further in the main file - simply importing my library module is sufficient.

A big thank you to Šimon Tóth for writing about this in his article on modules.

  • Related