Following instructions by Microsoft, I couldn't get the std module to build and not have a versioning error, so I went ahead and just added the file:
C:\Program Files\Microsoft Visual Studio\2022\Preview\VC\Tools\MSVC\14.35.32213\modules\std.ixx
to my project and I import it into my module interface files. My only issue is I can't access ::localtime_s because it is one of the static-inline/global functions not in the std namespace. Including <time.h> in the global module space creates issues with macro redefinitions. Is there something I am missing?
export module MyModule;
import std;
export namespace nspace1 {
void TimeFunction();
}
namespace nspace1 {
void TimeFunction()
{
std::time_t t = std::time(nullptr);
std::tm* now{};
void* result = ::localtime_s(now, &t); <== dne
}
}
The intellisense error is it is not found in the global space which makes sense for localtime_s because it is static, but _localtime64_s is just global and it says the same thing. Dropping the double colons just changes the error message to cannot be found.
The following code builds ok on my machine.
(Version 17.5.0 Preview 3.0)
import std; is a C++23 feature. I hope vendor support is getting better.
module;
#include <time.h>
export module MyModule;
import std;
export namespace nspace1 {
void TimeFunction();
}
namespace nspace1 {
void TimeFunction()
{
std::time_t t = std::time(nullptr);
std::tm* now{};
auto result = ::localtime_s(now, &t);
//auto result = localtime_s(now, &t); // ok, too
}
}
Related
This question might be too broad but it really tickled my mind lately:
I recently found out about modules in modern C++ : https://en.cppreference.com/w/cpp/language/modules
But I really don't get their purpose and when to use it instead of namespaces or just library headers?
In the example provided they now use import <iostream>; instead of include <iostream>;, what is the the difference in using one versus the other? Which one is to be preferred?
They say that "module are orthogonal to namespaces"? What does this mean?
What are the guidelines regarding development, should we now avoid headers and stuff ?
For instance:
helloworld.cpp
export module helloworld; // module declaration
import <iostream>; // import declaration
export void hello() // export declaration
{
std::cout << "Hello world!\n";
}
main.cpp
import helloworld; // import declaration
int main()
{
hello();
}
VERSUS
helloworld.h / helloworld.cpp
include <iostream>;
namespace ns
{
void hello();
}
#include "helloworld.h";
void ns::hello()
{
std::cout << "Hello world!\n";
}
main.cpp
#include "helloworld.h";
int main()
{
ns::hello(); // optionally "using namespace ns; to avoid ns::"
}
I'm actually trying to understand the C++20 modules system by writing my own little module. Let's say I want to provide a function that deletes all the spaces at the beginning and the end of a string (a trim function). The following code works without problem.
module;
export module String;
import std.core;
export std::string delete_all_spaces(std::string const & string)
{
std::string copy { string };
auto first_non_space { std::find_if_not(std::begin(copy), std::end(copy), isspace) };
copy.erase(std::begin(copy), first_non_space);
std::reverse(std::begin(copy), std::end(copy));
first_non_space = std::find_if_not(std::begin(copy), std::end(copy), isspace);
copy.erase(std::begin(copy), first_non_space);
std::reverse(std::begin(copy), std::end(copy));
return copy;
}
import std.core;
import String;
int main()
{
std::cout << delete_all_spaces(" Hello World! \n");
return 0;
}
But what if I want to use only specific headers instead of std.core in my module? If I do so, replacing the import std.core by the following code, I get an error on Visual Studio 2019.
module;
#include <algorithm>
#include <cctype>
#include <string>
export module String;
// No more import of std.core
export std::string delete_all_spaces(std::string const & string)
{
// ...
}
Error LNK1179 file not valid or damaged: '??$_Deallocate#$07$0A##std##YAXPAXI#Z' COMDAT duplicated
However, if in the main.cpp I remplace as well the import std.core with #include <iostream>, the code compiles again. It's like using both system provents the linker to do its job.
The question is: am I doing it wrong? Is it a bad practice to use both the new import and the old #include methods? I saw on multiple posts on the Internet that you can include some old headers in your module, thus modernizing your code without breaking the existing. But what if this header includes some part of the STL, like #include <string> but my module uses import std.core?
I'm testing only with Visual Studio 2019 because, as of now, import std.core does not work with GCC. So, may it comes from a bug in VS? Or will the problem be the same for all compilers?
Yes, modules can be used together with header files. we can both import and include headers in the same file, this is an example:
import <iostream>
#include <vector>
int main()
{
std::vector<int> v{1,6,8,7};
for (auto i:v)
std::cout<<i;
return 0;
}
When you create modules, you're free to export entities in the interface file of the module and move the implementations to other files. to conclude, the logic is the same as in managing .h and .cpp files
I am working on an old source code project which originally was written using MSVC 2008 and Boost 1.42, today I'm trying to port this to MSVC 2017 with Boost 1.73
There are many issues to resolve, one of which is below:
Severity Code Description Project File Line Suppression State
Error C3536 'binding': cannot be used before it is initialized Process Control Service Group processscope.cpp 197
The line that this occurs on:
auto binding = boost::bind(&IProcessChangeObserver::notify, _1, m_scope, change);
std::for_each(observers.begin(), observers.end(), binding);
Originally the assignment to binding was inline as the third parameter, it gives the same error. I can see why this is a problem, I cannot see why it ever worked?
Is there another way to write the above without the triggering a warning?
I've tried replacing with a standard loop:
for( std::list<boost::intrusive_ptr<IProcessChangeObserver> >::iterator itProc=objservers.begin();
itProc!=objservers.end(); itProc++ ) {
boost:bind(&IProcessChangeObserver::notify, itProc, m_scope, change);
}
To be honest I'm not 100% sure if this is a like for like replacement?
I have a suspicion the real problem is with binding which is likely not correctly initialized. There's bound to be more compiler messages about that.
It could be because Boost Bind stopped putting the _1 placeholders in the global namespace by default. You might detect this by adding -DBOOST_BIND_GLOBAL_PLACEHOLDERS to the compiler flags. However, heed the advice from the code:
BOOST_PRAGMA_MESSAGE(
"The practice of declaring the Bind placeholders (_1, _2, ...) "
"in the global namespace is deprecated. Please use "
"<boost/bind/bind.hpp> + using namespace boost::placeholders, "
"or define BOOST_BIND_GLOBAL_PLACEHOLDERS to retain the current behavior."
)
Minimal repro
See if you can reproduce with this minimal reproducer (I can't but I don't have access to the requisite versions ofr MSVC/Boost):
Live ON Coliru - GCC
Live On Rextester - MSVC
#include <algorithm>
#include <iostream>
#include <list>
#include <boost/bind/bind.hpp>
using namespace boost::placeholders;
#include <boost/intrusive_ptr.hpp>
#include <boost/smart_ptr/intrusive_ref_counter.hpp>
struct Scope {};
struct Change {};
namespace MyLib {
struct IProcessChangeObserver
: boost::intrusive_ref_counter<IProcessChangeObserver>
{
virtual ~IProcessChangeObserver() = default;
virtual void notify(Scope, Change) = 0;
};
struct Obs1 : IProcessChangeObserver {
void notify(Scope, Change) override { std::cout << "Obs1\n"; }
};
struct Obs2 : IProcessChangeObserver {
void notify(Scope, Change) override { std::cout << "Obs2\n"; }
};
}
using ObserverPtr = boost::intrusive_ptr<MyLib::IProcessChangeObserver>;
int main() {
using namespace MyLib;
std::list<ObserverPtr> observers {
new Obs1(), new Obs2(), new Obs1(),
};
Scope m_scope;
Change change;
auto binding = boost::bind(&IProcessChangeObserver::notify, _1, m_scope, change);
std::for_each(observers.begin(), observers.end(), binding);
}
Prints
Obs1
Obs2
Obs1
The actual fix was just to change _1 to std::placeholders::_1
I want to explain my question over an instance. I am using an third party library, having its own namespace. I want to import a part of this library, having its own namespace inside the namespace mentioned below.
namespace library {
namespace part {
}
}
There is also a hierarchy in the current project. I want to import and extend the library::part inside to my project with another name. I try to do as below:
#include <library/part>
namespace project {
namespace my_part = library::part;
}
namespace project {
namespace my_part {
void my_extension_1();
void my_extension_2();
}
}
The scenario can be done with the current tools of the language? If not, how should a workaround can be done? Still not, why?
Edit: Error message gcc 5.3.0 dumps:
error: conflicting declaration of namespace ‘project::my_part’
Edit: There is a suggestion about extending the original namespace, but that I am asking for. library::part users should not have a direct access to the functions I have added.
I believe you want to make a namespace of your own that contains
everything that library::part contains, and more besides, without
putting anything more into library::part. Like this?
namespace library {
namespace part {
const int library_part_i = 123;
}
}
namespace project {
namespace part {
using namespace library::part;
void my_extension_1(){};
void my_extension_2(){};
}
}
int main()
{
// const int i = library_part_i; <- Does not compile
// const int i = project::library_part_i; <- Does not compile
const int i = project::part::library_part_i;
// library::part::my_extension_1(); <- Does not compile
project::part::my_extension_2();
return 0;
}
I'm trying to take the approach of using swig with the main header file. It seems like swig will work doing this, but I've run into some problems. I asked a first question about it here on stackoverflow and while I haven't yet been successful, I've made enough progress to feel encouraged to continue...
So now, here's my interface file:
/* File : myAPI.i */
%module myAPI
%{
#include "stdafx.h"
#include <boost/algorithm/string.hpp>
... many other includes ...
#include "myAPI.h"
#include <boost/algorithm/string/predicate.hpp>
#include <boost/filesystem/path.hpp>
#include <boost/filesystem/operations.hpp>
using boost::format;
using namespace std;
using namespace boost::algorithm;
using namespace boost::serialization;
%}
/* Let's just grab the original header file here */
%include "myAPI.h"
As far as I can tell swig runs just fine. However, in the generated code it produces numerous definitions like this one:
SWIGINTERN int Swig_var_ModState_set(PyObject *_val) {
{
void *argp = 0;
int res = SWIG_ConvertPtr(_val, &argp, SWIGTYPE_p_MY_API, 0 | 0);
if (!SWIG_IsOK(res)) {
SWIG_exception_fail(SWIG_ArgError(res), "in variable '""ModState""' of type '""MY_API""'");
}
if (!argp) {
SWIG_exception_fail(SWIG_ValueError, "invalid null reference " "in variable '""ModState""' of type '""MY_API""'");
} else {
MY_API * temp;
temp = reinterpret_cast< MY_API * >(argp);
ModState = *temp;
if (SWIG_IsNewObj(res)) delete temp;
}
}
return 0;
fail:
return 1;
}
Visual Studio 2010 complains with an error for each of these code blocks. The error is based on the temp var:
2>c:\svn\myapi\myapi_wrap.cxx(3109): error C2071: 'temp' : illegal storage class
I tried just to add a global declaration of this variable as an int to the swig generated _wrap.cxx file, but it didn't not work. (clearly a naive approach...).
Does anyone have some insight as to what I need to do to avoid this error?
Thanks in advance!