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.
Related
I have a embedded C++03 codebase that needs to support different vendors of gadgets, but only ever one at a time. Most of the functions overlap between the several gadgets, but there are a few exclusives, and these exclusive functions are creating a problem that I need to solve.
Here is an example of clumsy code that works using pre-processor conditionals:
#define HW_TYPE1 0
#define HW_TYPE2 1
#define HW_TYPE HW_TYPE1
struct GadgetBase {
void FncA();
// Many common methods and functions
void FncZ();
};
#if HW_TYPE==HW_TYPE2
struct Gadget : public GadgetBase {
bool Bar() {return(true);}
};
#else
struct Gadget : public GadgetBase {
bool Foo() {return(false);}
};
#endif
Gadget A;
#if HW_TYPE==HW_TYPE2
bool Test() {return(A.Bar());}
#else
bool Test() {return(A.Foo());}
Here is my attempt at converting the above code to C++ templates without pre-processor directives.
The following code does not compile due to an error in the definition of Test() on my particular platform, because either Foo() or Bar() is undefined depending on the value of Type.
enum TypeE {
eType1,
eType2
};
const TypeE Type= eType1; // Set Global Type
// Common functions for both Gadgets
struct GadgetBase {
void FncA();
// Many common methods and functions
void FncZ();
};
// Unique functions for each gadget
template<TypeE E= eType1>
struct Gadget : public GadgetBase {
bool Foo() {return(false);}
};
template<>
struct Gadget<eType2> : public GadgetBase {
bool Bar() {return(true);}
};
Gadget<Type> A;
template<TypeE E= eType1>
bool Test() {return(A.Foo());}
template<>
bool Test() {return(A.Bar());}
I want to do this with templates to keep the number of code changes down when a new type or additional functions are added. There are currently five types with at least two more expected soon. The pre-processor implementation code reeks, I want to clean this up before it gets unwieldy.
The gadget code is a small amount of the total code base, so breaking up the entire project per gadget may not be ideal either.
Even though only one type will ever be used for each project, the unused types still have to compile, how do I best design this using C++03 (no constexpr, const if, etc)? Am I completely approaching this wrongly? I am willing to do a complete overhaul.
EDIT:
Tomek's solution below makes me wonder if it violates LSP. Effectively, another way to look at this is having Test() be part of an interface that requires implementation. So, the example can be reconsidered like the following:
struct GadgetI {
virtual bool Test()=0;
};
template<TypeE E= eType1>
struct Gadget : public GadgetBase, public GadgetI {
bool Foo() {return(false);}
bool Test() {return Foo();}
};
template<>
struct Gadget<eType2> : public GadgetBase, public GadgetI {
bool Bar() {return(true);}
bool Test() {return Bar();}
};
template<>
struct Gadget<eType3> : public GadgetBase, public GadgetI {
bool Test() {} // Violation of LSP?
};
Or similarly with the edited example:
template<typename T>
bool Test(T& o) {} // Violation?
template<>
bool Test(Gadget<eType1> &o) {return(o.Foo());}
template<>
bool Test(Gadget<eType2> &o) {return(o.Bar());}
Test(A);
I might be over-thinking this, I just don't want a poor design now to bite me later.
I agree the code looks convoluted, I'm with you there. But I believe you are going in the wrong direction. Templates seem cool but they are not the right tool in this case. With templates you WILL always compile all the options every time, even if they are not used.
You want the opposite. You want to ONLY compile one source at a time. The proper way to have the best of both worlds is to separate each implementation in a different file and then pick which file to include/compile using external methods.
Build systems usually have plenty of tools for this respect. For example, for compiling natively, we can rely on CMAKE's own CMAKE_SYSTEM_PROCESSOR to identify which is the current processor.
If you want to cross compile you need to specify which platform you want to compile to.
Case in mind, I have a software that needs to be compiled in many operating systems like Redhat, CentOS, Ubuntu, Suse and Windows/Mingw. I have one bash script file that checks for the environment and loads a toolchain cmake file specific for that operating system.
Your case seems to be even simpler. You could just indicate which platform you'd like to use and instruct the build system to compile just the file specific to that platform.
You are getting there :).
Rewrite your Test function so it doesn't rely on global Gadget object but instead takes one as a templated parameter:
template<class T>
bool Test(T &o, std::integral_constant<bool (T::*)(), &T::Foo> * = 0)
{
return(o.Foo());
}
template<class T>
bool Test(T &o, std::integral_constant<bool (T::*)(), &T::Bar> * = 0)
{
return(o.Bar());
}
And call it as:
Test(A);
This relies on SFINAE (Substitution Failure Is Not An Error) idiom. Based on the definitions compiler will deduce the type of T to be a Gadget. Now, depending on availability of the Foo and Bar function it will pick one of the overloads.
Please note this code WILL BREAK if both Foo and Bar are defined in Gadget as the two overloads will match.
This brings a question if you just can't wrap calls to Foo and Bar inside a Gadget class:
template<TypeE E= eType1>
struct Gadget : public GadgetBase {
bool Foo() {return(false);}
bool Test() {return Foo();}
};
template<>
struct Gadget<eType2> : public GadgetBase {
bool Bar() {return(true);}
bool Test() {return Bar();}
};
and consistently call A.Test() instead?
EDIT:
I might have over-complicated it. The following overload may be an easier approach to this:
bool Test(Gadget<eType1> &o)
{
return(o.Foo());
}
bool Test(Gadget<eType2> &o)
{
return(o.Bar());
}
Test(A);
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(); }
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).
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.
Very new to c++ having trouble calling a function from another class.
Class B inherits from Class A, and I want class A to be able to call a function created in class B.
using namespace std;
class B;
class A
{
public:
void CallFunction ()
{
B b;
b.bFunction();
}
};
class B: public A
{
public:
virtual void bFunction()
{
//stuff done here
}
};
It all looks fine on screen (no obvious errors) but when I try to compile it i get an error C2079 'b' uses undefined class B.
I've tried making them pointers/ friends but I'm getting the same error.
void CallFunction ()
{ // <----- At this point the compiler knows
// nothing about the members of B.
B b;
b.bFunction();
}
This happens for the same reason that functions in C cannot call each other without at least one of them being declared as a function prototype.
To fix this issue we need to make sure both classes are declared before they are used. We separate the declaration from the definition. This MSDN article explains in more detail about the declarations and definitions.
class A
{
public:
void CallFunction ();
};
class B: public A
{
public:
virtual void bFunction()
{ ... }
};
void A::CallFunction ()
{
B b;
b.bFunction();
}
What you should do, is put CallFunction into *.cpp file, where you include B.h.
After edit, files will look like:
B.h:
#pragma once //or other specific to compiler...
using namespace std;
class A
{
public:
void CallFunction ();
};
class B: public A
{
public:
virtual void bFunction()
{
//stuff done here
}
};
B.cpp
#include "B.h"
void A::CallFunction(){
//use B object here...
}
Referencing to your explanation, that you have tried to change B b; into pointer- it would be okay, if you wouldn't use it in that same place. You can use pointer of undefined class(but declared), because ALL pointers have fixed byte size(4), so compiler doesn't have problems with that. But it knows nothing about the object they are pointing to(simply: knows the size/boundary, not the content).
So as long as you are using the knowledge, that all pointers are same size, you can use them anywhere. But if you want to use the object, they are pointing to, the class of this object must be already defined and known by compiler.
And last clarification: objects may differ in size, unlike pointers. Pointer is a number/index, which indicates the place in RAM, where something is stored(for example index: 0xf6a7b1).
class B is only declared but not defined at the beginning, which is what the compiler complains about. The root cause is that in class A's Call Function, you are referencing instance b of type B, which is incomplete and undefined. You can modify source like this without introducing new file(just for sake of simplicity, not recommended in practice):
using namespace std;
class A
{
public:
void CallFunction ();
};
class B: public A
{
public:
virtual void bFunction()
{
//stuff done here
}
};
// postpone definition of CallFunction here
void A::CallFunction ()
{
B b;
b.bFunction();
}
in A you have used a definition of B which is not given until then , that's why the compiler is giving error .
Forward declare class B and swap order of A and B definitions: 1st B and 2nd A. You can not call methods of forward declared B class.
Here's my solution to the issue. Tried to keep it straight and simple.
#include <iostream>
using namespace std;
class Game{
public:
void init(){
cout << "Hi" << endl;
}
}g;
class b : Game{ //class b uses/imports class Game
public:
void h(){
init(); //Use function from class Game
}
}A;
int main()
{
A.h();
return 0;
}
You can also have a look at the curiously recurring template pattern and solve your problem similar to this:
template<typename B_TYPE>
struct A
{
int callFctn()
{
B_TYPE b;
return b.bFctn();
}
};
struct B : A<B>
{
int bFctn()
{
return 5;
}
};
int main()
{
A<B> a;
return a.callFctn();
}