C++20 modules TS: still need function declaration? - c++

I hope a quick small question to those who tried C++20 modules
According to TS, should this code compile in C++20?
void f1() { f2(); }
void f2() { ... }
For example, in C++11 it won't compile, because f1() doesn't "know" about the f2(), f2() must be declared before usage.
But maybe in C++20 this requirement will be eliminated in modules?
If the first code snippet is not compiled, will this one compile
void f1() { f2(); }
export void f2() { ... }
because f2() will be seen from the BMI?

While Modules does change many things about name lookup (the latest paper I'm aware of is P1103R1), Modules will not change the fundamental property of C++ that names must be declared before use (modulo things like dependent unqualified calls - which simply delays the lookup, but it still has to actually happen).
This:
void f1() { f2(); }
export void f2() { ... }
will still be a compile error if there is no previous declaration of f2 or it wasn't imported from somewhere. You'll have to write:
export void f2() { ... }
void f1() { f2(); }

Related

How to automatically rewrite c++ code with semantic informations?

What I want is applying a transform just like { {ObjA}.func1() -> {ObjA}.func2() | for all {ObjA} is {SpecClass}}. That is, transforming all objects of type SpecClass's function call to A::func1() to A::func2().
Obviously it needs semantic information to do this. Are there any existing tools to do things like this(, or maybe even more powerful)? Or I need to develop one using Clang-LibTooling or what?
Before transformation:
struct A{
void f();
void g();
};
struct B{
void f();
void g();
};
void foo()
{
A a;
B b;
a.f();
b.f();
}
After transformation:
struct A{
void f();
void g();
};
struct B{
void f();
void g();
};
void foo()
{
A a;
B b;
a.g();
b.f();
}
Assuming I interpret the question correctly (i.e., as applying this on the source code) this is commonly done in IDEs.
E.g., Visual Studio can rename a member function func1 to func2 and then all calls ObjA.func1() will be changed to ObjA.func2().
If func2 already exist then:
Change func2 to func2dummy - without using refactoring
Rename func1 to func2 - using refactoring
Change func2 back to func1 and func2dummy back to func2 - without using refactoring
Other refactoring tool, including ones built on llvm, can likely do the same.

C++20 template compilation passes

I am having a problem with the changes that were made to the way C++ templates are compiled, between the C++17 and 19 standards. Code that used to compile in VS2017 throws a compiler error since I upgraded to VS2019 or VS2022.
Situations have to do with the fact that the compiler now runs a basic syntax check on the template definition when it sees this definition ("first pass") and not only when the template is actually used.
Code example 1:
class Finder
{
template<typename T>
T convert_to(HANDLE h)
{
return Converters::Converter<T>::Convert(get_data(h));
}
};
Here, the template class Converter<> resides in namespace Converters, and get_data is a member function of Finder which returns something that can be passed into the Convert function.
Since we're dealing with templates, this code sits in a header file "Finder.h". The header file doesn't #include "Converters.h". Finder.h is shared across several projects, some of which don't even know the Converters.h file namespace.
As long as no code calls the MyClass::convert_to<> function, this compiles in VS2017, but not so in VS2019 and VS2022:
error C3861: 'Converters': identifier not found
The obvious solution is, of course, to #include "Converters.h" either in this header file, or in the precompiled headers file. However, as was said, Converters.h is not known in all places which use MyClass. Another solution would be to use archaic #define CONVERTERS_H in the Converters.h header and enclose the function definition in #ifdef CONVERTERS_H, but this looks really ugly.
My question is: Is there a way to prevent the compiler from doing this "first pass"? Or to re-write this code so that it compiles? I don't mind if it's MS specific; no other compiler will ever see the code.
Code example 2:
class MyClass2
{
template<class T>
static void DoSomething(T* ptr) { static_assert(false, "Don't do this"); }
// lots more member functions, most of them 'static'
};
template<> void MyClass::DoSomething(CWnd* ptr) { /*some useful code*/ }
/// and some more specializations of DoSomething
The intention is that the static_assert should emit an error message whenever DoSomething is called with an argument for which no explicit specialization of this template function is defined. This worked in VS2017, but in VS2022, the "first pass" of the compiler triggers the static_assert.
Again, I wonder how I could achieve this effect, other than by replacing the static_assert by a run-time assertion.
Or am I thinking into a completely wrong direction?
Thanks
Hans
The first case requires a forward declaration of some kind, that's unavoidable.
The second case, though, can be handled with just a minor change.
#include <type_traits>
class CWnd {};
class MyClass2
{
public:
template<class T, class Y=T>
static void DoSomething(T* ptr) { static_assert(!std::is_same_v<Y,T>, "Don't do this"); }
};
template<> void MyClass2::DoSomething(CWnd* ptr) { /*some useful code*/ }
void foo()
{
int a;
CWnd b;
MyClass2::DoSomething(&a); // ERROR
MyClass2::DoSomething(&b); // OK
}
(partial answer)
To fix MyClass2, the usual trick is to make false depend on T, so that the first pass does not trigger the assert.
// dependent false
template <typename>
constexpr bool dep_false() { return false; }
class MyClass2
{
template<class T>
static void DoSomething(T* ptr) {
static_assert(dep_false<T>(), "Don't do this");
}
// lots more member functions, most of them 'static'
};
// specialization example
template<>
void MyClass2::DoSomething<int>(int* ptr) {
std::cout << "int* is OK\n";
}

Calling static methods in constructor

This seems a bit strange to me. Since a static method can have an instance of the class, one naturally expects that the compiler should not allow calling static methods inside the constructor. But I have tested the following code with every compiler and ironically, none of them gave me a single warning. Although in execution time they all throw exceptions. Am I missing something here?
#include <iostream>
class Foo
{
public:
inline Foo()
{
std::cout << "testing: var = " << bar() - 1 << '\n';
}
~Foo(){}
static int bar()
{
Foo f;
f.var = 10;
return f.test();
}
private:
int var;
int test()
{
return var + 1;
}
};
int main()
{
Foo foo;
return 0;
}
Live example
It is not illegal to call static functions from within the constructor. Only, you are getting a stack overflow, if you do it like you do. This results in
Foo() calls bar();
bar() calls Foo();
Foo() calls bar();
bar() calls Foo();
...
Until no stack is left.
This is exactly the same as if you had:
void f1();
void f2()
{
f1();
}
void f1()
{
f2();
}
int main(int, char*[])
{
f1();
return 0;
}
Only two global functions, nothing more. Would have been all the same in C, too (but you have do declare void f(void) there), or Java, C#, perl, python, ...
What warnings are you expecting? What you've written is an infinite recursion which has nothing to do with static member functions. You can do it with any other function inside or outside a class.
Static functions are not much different from the free ones. So free functions should also be banned from constructor? There is no point in forbidding to call static functions from constructors.
There is no reason not to call a static (or in fact a non-static) member function in a constructor (although it is not recommended to call virtual functions).

C++ Is there a way to work around circular dependency?

Now I know that in C++ everything has to be declared before it can be used. But what if I have two functions that reference each other?
For example:
void func1() {
func2();
}
void func2() {
func1();
}
Is it completely impossible to do this?
A forward declaration is exactly what you want:
void func2(); // forward declare func2
void func1() {
func2();
}
void func2() {
func1();
}
The first void func2(); is called a forward declaration. You promise that you will define it according to this prototype eventually.
You need to forward declare func2() to be able to use it in func1():
void func2();
void func1() {
func2();
}
void func2() {
func1();
}
Now at the point where func1() references func2(), func2() has been declared, and at the point where func2() references func1(), func1() will have been declared.
However, calling either one of the two functions will cause an infinite loop, which will result in a stack overflow.
Is that snippet of code impossible without some sort of forward declaration? Yes. Think about it, when the compiler gets here:
void func1() {
func2();
}
He has never seen func2 before, and therefore can't compile it.
Most people create a .h file that contains function declarations so you can avoid this type of thing. For example,
foo.h
void func1();
void func2();
foo.c
#include "foo.h"
void func1() {
func2();
}
void func2() {
func1();
}
You should accept one of the other answers because that's how the language C++ works and there's nothing to do about it, if your concern is that writing lots of forwards is a pain, you should note that several frameworks already provide headers just for the sake of forward declaring stuff so that users don't have too.
This is for convenience when there's really a lot of stuff that is forward declared or there's stuff that need to be declared correctly (in example templates, aliases and also I saw some macro trickery once in a while).
Also generally you have to put declarations and definitions in different files to avoid recompiling where possible and generally to make the project more clear and manageable.
Functions.hpp
void func();
void func2();
Functions.cpp
#include "Functions.hpp"
void func(){
func2();
}
void func2(){
func();
}
user code:
main.cpp
#include "Functions.hpp"
int main(){
func();
return 0;
}
Also note that you have some confusion about "Declaration" and "Forward Declaration".
Actually when you put a function signature in your code your are Declaring it:
int function3(); // function declared
Forward declaration is about telling a class exists without telling anything more about its signature:
class myclass; //forward declaration
//possible declarations using "myclass" forward declaration
int function4(myclass & ref);
int function5(myclass * ref);
Forward declaration is used to keep headers simple and reducing compile time (a lot in certain cases) by moving unneeded details to implementation (.cpp) files.
You can simply place one function inside the other, then expressed as a (usually static) member function of a class, or as a lambda.
This assuming that the top-level calls from elsewhere are always to one of the functions.
Another possibility, with both functions available to the top-level calling code, is to place both functions as (most naturally static) members of a class, where they can be defined inline.
But I think it's more clean to just use the forward declaration.
There isn't really any good reason to avoid it, so a workaround like one of those mentioned above would just make other programmers waste some time scratching their heads – what on Earth is this for?
Amendment: example of the class scope approach:
struct Recursive
{
static void func1() { if( some_condition ) { func2(); } }
static void func2() { if( some_condition ) { func1(); } }
};
Example of the nested functions approach:
void func1()
{
const auto func2 = []{ if( some_condition ){ func1(); } }
if( some_condition ) { func2(); }
}
It's certainly possible with member functions. For example:
class A {
void func1() {
func2();
}
void func2() {
func1();
}
};
It can be more problematic if you need two classes to know about each other but does that answer your question?
Edit: You don't need the member function declarations before their definitions.

Exception specifications are not compatible in declaration and in realisation of function

We have following code
int main()
{
void f() throw(int);
f();
return 0;
}
void f() { }
GCC and clang compiles it well. But, in standard there is such paragraph:
n3376 15.4/4
If any declaration of a function has an exception-specification that is not a noexcept-specification allowing
all exceptions, all declarations, including the definition and any explicit specialization, of that function shall have a compatible exception-specification.
And for following example: gcc - error, clang - warning
void f() throw(int);
int main()
{
f();
return 0;
}
void f() { }
Why there is difference in these snippets? Thanks.
The n3376 15.4/4 from the std specifie that all déclarations and definitions of a function must have the same throwing type. Here :
void f() throw(int);
int main()
{
f();
return 0;
}
void f() { }
the declaration void f() throw(int); and the definition void f() { } are in global scop. So they are in conflict because the declaration is for a function which throw int while the definition is for a function without a throw specification.
Now, when you put the declaration in the main scop, the definition isn't in the same scop, during this scop the definition isn't known so you can compile.
I hope you understood my english, sorry about it.