Here is the code:
namespace Test {
/// Base class
class Base
{
public:
/// Method foo
/// #param a ParamA
/// #param b ParamB
virtual void foo(char a, int b);
/// Method foo
/// #param a ParamA
/// #param b ParamB
/// #param c ParamC
virtual void foo(char a, int b, char c);
/// Method foo
/// #param m ParamM
template<typename T>
void foo(std::vector<T> m)
{
}
};
/// Derived class
class Derived : public Base
{
public:
using Base::foo;
/// Method foo
/// #param a ParamA
/// #param b ParamB
void foo(char a, int b) override;
};
}
If this code will be processed with Doxygen. We get the strange error:
Error: argument 'm' of command #param is not found in the argument list of Test::Derived::foo(typename T) (warning treated as error, aborting now)
If commenting line using Base::foo; the Doxygen correctly processing this file.
Looks like a bug in Doxygen, but is anybody know a workaround for that?
With the doxygen versions till doxygen 1.9.1 (inclusive) I was able to reproduce the problem.
The problem is gone with the versions 1.9.2 and higher.
The current doxygen version is 1.9.4 (5d15657a55555e6181a7830a5c723af75e7577e2)
The solution for this problem is to update your doxygen version to the current doxygen version.
I am building a matlab MEX function using the matlab c++ data api. My mex function accepts a struct with some fields of varying size, type and name as an input. The exact makeup of this struct could vary and is defined outside the scope of the program, but I know all the possible combinations of the constituent fields ahead of time. We will call this parameter called 'Grid', and Grid is passed to a helper function.
In this helper function, I would like to generate an instance of a derived class where the specific type of derived class will either depend on/correspond to the specific combination of the fields of Grid. The idea is that I can extract the fields of Grid and use them to create the instance of the correct derived class. I would like to achieve this without the need to rewrite my code every time I add a new derived class with a different possible combination of fields. How could I do this? I am open to alternate approaches and strategies as well.
For example, Grid might be defined in the matlab environment like:
Grid = struct('XPSF',X(:),'ZPSF',Z(:),'xe',Trans.ElementPos(:,1)*wvlToM,'TXDelay',TXdelay(:,8));
Then handled by the mex function and passed to the helper function whose definition looks like:
void extractFields(matlab::data::StructArray& Grid);
Currently, Grid can also be composed of a single value in place of XPSF or ZPSF. I anticipate possibly adding other fields to Grid in the future. For each of these possible combinations, I have a derived class that has some unique overridden functions:
class Beamform {
public:
//Constructor
Beamform();
virtual ~Beamform() {}
template <typename T> int sgn(T val) { return (T(0) < val) - (val < T(0)); }
virtual void calcIDXT(...);
};
class bfmPlaneWave : public Beamform
{
public:
double theta;
Eigen::VectorXd xe, XPSF, ZPSF, dTX;
template<typename Derived>
bfmPlaneWave(double& angle, ...);
template<typename Derived>
void calcIDXT(...) override;
};
class bfmXRflMTX : public Beamform {
public:
double theta, zCoord;
Eigen::VectorXd xe, XPSFin, XPSFout, dTX;
template<typename Derived>
bfmXRflMTX(double& angle, ...);
template<typename Derived>
void calcIDXT(...) override;
};
class bfmZRflMTX : public Beamform {
public:
double theta, xCoord;
Eigen::VectorXd xe, ZPSFin, ZPSFout, dTX;
template<typename Derived>
bfmXRflMTX(double& angle, ...);
template<typename Derived>
void calcIDXT(...) override;
};
I would start by declaring a common pattern for construction. Something like this:
class Beamform
{
public:
virtual void calcIDXT(...) = 0;
virtual ~Beamform() = default;
};
class bfmPlaneWave: public Beamform
{
public:
/** Return nullptr if not compatible */
static bfmPlaneWave* fromGrid(matlab::data::StructArray&);
virtual void calcIDXT(...) override;
};
class bfmXRflMTX: public Beamform
{
public:
/** Return nullptr if not compatible */
static bfmXRflMTX* fromGrid(matlab::data::StructArray&);
virtual void calcIDXT(...) override;
};
Then you could have a simple, central factory function that you extend as required:
/**
* Option 1: Use a central dispatch function which can be updated with a
* simple two-liner
*/
std::unique_ptr<Beamform> beamformForGrid(matlab::data::StructArray& Grid)
{
std::unique_ptr<Beamform> rtrn;
if(rtrn.reset(bfmPlaneWave::fromGrid(Grid)), rtrn != nullptr)
return rtrn;
if(rtrn.reset(bfmXRflMTX::fromGrid(Grid)), rtrn != nullptr)
return rtrn;
// insert more here
return rtrn;
}
However, if I understand you correctly, this is something that you don't want. In that case you could use a central registry and global constructors. Global constructors (those for global variables) are run when a DLL is loaded. This is similar to how for example CppUnit registers its unit tests.
class AbstractBeamformFactory
{
public:
virtual ~AbstractBeamformFactory() = default;
/** Return nullptr if not compatible */
virtual Beamform* fromGrid(matlab::data::StructArray&) = 0;
};
/**
* Registers existing factories
*
* Follows the singleton pattern.
* Yes, it is frowned upon, but if it works, it works.
*/
class BeamformRegistry
{
/**
* Protects the list of factories
*
* A bit overkill seeing how neither Matlab nor global constructors are
* particularly multithreaded, but better safe than sorry
*/
mutable std::mutex mutex;
std::vector<AbstractBeamformFactory*> factories;
public:
/**
* Retrieves singleton instance
*
* This isn't a global variable because we need to use it in other
* global constructors and we can't force a specific order between
* global constructors
*/
static BeamformRegistry& globalInstance();
void add(AbstractBeamformFactory* factory)
{
std::lock_guard<std::mutex> lock(mutex);
factories.push_back(factory);
}
void remove(AbstractBeamformFactory* factory)
{
std::lock_guard<std::mutex> lock(mutex);
factories.erase(std::find(factories.begin(), factories.end(), factory));
}
std::unique_ptr<Beamform> beamformForGrid(matlab::data::StructArray& Grid) const
{
std::unique_ptr<Beamform> rtrn;
std::lock_guard<std::mutex> lock(mutex);
for(AbstractBeamformFactory* factory: factories)
if(rtrn.reset(factory->fromGrid(Grid)), rtrn != nullptr)
break;
return rtrn;
}
};
/**
* Implements AbstractBeamformFactory for a specific type of beamformer
*
* Create a global variable of this type in order to add it to the global
* BeamformRegistry
*/
template<class BeamformImplementation>
class BeamformFactory: public AbstractBeamformFactory
{
bool registered;
public:
explicit BeamformFactory(bool registerGlobal=true)
: registered(registerGlobal)
{
/* don't move this to the base class to avoid issues around
* half-initialized objects in the registry
*/
if(registerGlobal)
BeamformRegistry::globalInstance().add(this);
}
virtual ~BeamformFactory()
{
if(registered)
BeamformRegistry::globalInstance().remove(this);
}
virtual Beamform* fromGrid(matlab::data::StructArray& Grid) override
{ return BeamformImplementation::fromGrid(Grid); }
};
/* in CPP files */
BeamformRegistry& BeamformRegistry::globalInstance()
{
static BeamformRegistry instance;
return instance;
}
/*
* Make global variables to add entries to registry.
* These can be scattered across different cpp files
*/
BeamformFactory<bfmPlaneWave> planeWaveFactoryInstance;
BeamformFactory<bfmXRflMTX> XRflMTXFactoryInstance;
Now you can simply call BeamformRegistry::globalInstance().beamformForGrid(Grid) to access all registered beamform implementations and to extend the number of implementations, you just scatter factory instances across your cpp files.
One thing I'm unsure about is how this interacts with MEX. When does Matlab load its extensions? If this only happens in some form of lazy fashion, the global constructors may not execute soon enough. I guess it is worth checking with a few print statements.
If I have a macro as such
#define FOO(x) void x()
That I would us as such
class Test {
public:
/*
* #brief My func1
*/
FOO(func1);
/*
* #brief My func2
*/
FOO(func2);
};
Is there a way to have Doxygen, when it expands to FOO macro, put each expanded function into a group?
For example, I would like the macro expansion + Doxygen to result in something equivalent to if I have written:
class Test {
public:
/**
* #name MyGroup
* #{
*/
/*
* #brief My func1
*/
void func1();
/** #} */
/**
* #name MyGroup
* #{
*/
/*
* #brief My func1
*/
void func2();
/** #} */
};
Thus, I would like some way to have Doxygen document that all the functions generated by the macro are grouped together while still maintaining the comments for each individual function.
Please let me know if this does not make sense.
I would like to write a custom clang-tidy check to port code from cppunit to googletest.
class SomeTest: public CPPUNIT_NS::TestFixture {
CPPUNIT_TEST_SUITE(SomeTest);
CPPUNIT_TEST(shouldDoSomething);
CPPUNIT_TEST_SUITE_END();
...
protected:
void shouldDoSomething();
void otherFunction(int times = 0);
};
CPPUNITFRAMEWORK_TEST_SUITE_REGISTRATION(SomeTest);
...
void SomeTest::shouldDoSomething() {...}
void SomeTest::otherFunction(int) {}
I would like to be able to replace
void SomeTest::shouldDoSomething() {...}
with
TEST_F(SomeTest, shouldDoSomething) {...}
I can match a function name from CPPUNIT_TEST(...) macro with
stringLiteral(hasAncestor(callExpr(callee(functionDecl(hasName("getTestNameFor"))))))
but I have no idea whether it is possible to reuse this information to match the function declaration so I can actually replace it with googletest.
so I've been learning C++ for a few weeks now but I'm having a bit of trouble:
Class Tool
{
public:
Tool(const float maxCarried = 1):maxAmountCarried(maxCarried){}
virtual void Use() = 0;
/* ... */
}
Class CuttingTool: public Tool
{
public:
CuttingTool(const float maxCarried):Tool(maxCarried){}
virtual void Use(){ /* ... */ }
/* ... */
}
Class Saw: public CuttingTool
{
public:
Saw(const float maxCarried):CuttingTool(1){}
virtual void Use(){ /* ... */ }
/* ... */
}
Class Scissors: public Fruit
{
public:
Scissors(const float maxCarried):CuttingTool(2){}
virtual void Use(){ /* ... */ }
/* ... */
}
A few things to note:
I'm trying to make a big database of 'Tools'.
I never change the value of 'maxAmountCarried' so I've set it to const.
Memory/performance is important because I have a huge vector of Tools.
The problem lies within the fact that I have to keep writing:
ClassName(const float maxCarried):BaseClass(maxCarried){}
It's really tedious, moreover, I worry that if I were to add a new const value I would have to repeat the process all over again (problem when you have 50 classes inheriting from Food :S).
I feel as though I've designed this poorly. Is there a way to avoid repeating the same line of code over and over again or do I just have to suck it up and deal with it?
Thanks in advance.
If your only concern is the repeating initialization list you could use a macro like this:
#define DEFAULT_CONSTRUCTOR(Child, Parent) Child(float max) : Parent(max) {}
and use it like so:
class Saw : public CuttingTool
{
public:
DEFAULT_CONSTRUCTOR(Saw, CuttingTool) {}
};
You can extend this idea and do something like that:
#define BEGIN_CLASS(Child, Parent) class Child : public Parent { \
public: \
Child(float max) : Parent(max) {}
#define END_CLASS };
and declare your classes:
BEGIN_CLASS(Scissors, Tool)
void cut_through_paper() {} // specific method for scissors
END_CLASS
Note that there is no point of using const float as a parameter since you can't change arguments passed by value anyway. You might however want to use const float& to pass an argument by reference, and that will make sense if size of float is bigger than the size of a pointer in your specific platform.
If you never change you max value, you can make it static and share it between all tool instances:
class Tool
{
protected:
static const float _max;
public:
Tool() {}
};
const float Tool::_max = 0;
If you'd like to be able to change max value only once (say at the begining of your program, you can add a static function:
static void globalMax(float max) { Tool::_max = max; }
and use it where appropriate:
int main() {
Tool::globalMax(5);
...
...
}
Note that you should remove the const from the _max declaration.
Finally, if performance is an issue, you probably need to rethink your design and maybe go with something else (templates maybe?)
Hope that helps!