Clang AST Matcher: No CXXMethodDecl for `operator()`? - clang

I have the following struct definition in a file:
template <class... EventArgs>
struct banana {
template <class... Args>
void operator()(Args&&... args) const {
_f(std::forward<Args>(args)...);
}
private:
std::function<void(EventArgs...)> _f;
};
Using -ast-dump -fsyntax-only, I can clearly see multiple CXXRecordDecls in the dump that refer to banana, as well as CXXMethodDecls that refer to operator():
`-ClassTemplateDecl 0x7fb23c11e028 <./test_files/templates.cpp:12:1, line:21:1> line:13:8 banana
|-TemplateTypeParmDecl 0x7fb23c11df08 <line:12:11, col:20> col:20 referenced class depth 0 index 0 ... EventArgs
|-CXXRecordDecl 0x7fb23c11df90 <line:13:1, line:21:1> line:13:8 struct banana definition
| |-CXXRecordDecl 0x7fb23c11e300 <line:13:1, col:8> col:8 implicit struct banana
| |-FunctionTemplateDecl 0x7fb23c11e668 <line:14:5, line:17:5> line:15:10 operator()
| | |-TemplateTypeParmDecl 0x7fb23c11e398 <line:14:15, col:24> col:24 referenced class depth 1 index 0 ... Args
| | `-CXXMethodDecl 0x7fb23c11e5d0 <line:15:5, line:17:5> line:15:10 operator() 'void (Args &&...) const'
| | etc., etc.
My MatchFinder::MatchCallback subclass is being run over the CXXRecordDecl for event, however methods() is coming back with an empty range:
void ClassInfo::run(const MatchFinder::MatchResult& Result) {
auto clas = Result.Nodes.getNodeAs<clang::CXXRecordDecl>("class");
for (const auto& method : clas->methods()) {
// Not getting run - methods() is empty?
}
}
What am I missing?

Well, clas->methods() only returns CXXMethodDecls in the top level of the struct.
But in your struct, there is only FunctionTemplateDecl.
So, you may wanna do something like this:
for (const auto &decl : clas->decls()) {
if (auto *templ = dyn_cast<FunctionTemplateDecl>(&decl)) {
// Use templ->getTemplatedDecl to get FunctionDecl.
}
}
Note. I haven't actually tested nor compiled that code, but hopefully, you get the idea from it.

Related

How to create a linked list using a struct inside the node element

I tried to create a linked list, using a node that had a structure inside it to hold the info data. Whenever I try to do that , I have a compiled error telling me that I am using an "incomplete" type, and I am not sure why.
The exact error I have is the following:
main.c: In function ‘createList’:
main.c:53:46: error: invalid application of ‘sizeof’ to incomplete type ‘typeNode’ {aka ‘struct StructInfoNodo’}
53 | if ((new_node = (typeNode *) malloc (sizeof (typeNode))) == NULL)
| ^~~~~~~~
main.c:59:9: error: dereferencing pointer to incomplete type ‘typeNode’ {aka ‘struct StructInfoNodo’}
59 | new_node->info.idCell=nodeinfo.idCell;
| ^~
main2.c:67:5: warning: statement with no effect [-Wunused-value]
67 | list->num_nodes;
| ~~~~^~~~~~~~~~~
In my code, I have a createList funtion, which tries to create the first node of the list, using some sample data. However, I am unable to the initial malloc, seems it does not recognize the new type that was defined (typeNet) to hold the info inside a structure.
I was using for that the following instruct: new_node = (typeNode *) malloc (sizeof (typeNode))
and after that, I was trying to do new_node->info.idCell=nodeinfo.idCell;
That lines result in the errors shown above.
Any idea on how I can solve it, and be able to write info on the node?
Please find below the complete code:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define MAXCHAR 80
struct structInfoNet
{
int idCell;
char MacAddress[MAXCHAR];
char Essid[MAXCHAR];
char Mode[MAXCHAR];
int Channel;
};
typedef struct structInfoNet typeNet;
struct structInfoNode
{
typeNet info;
struct structInfoNode* nextNode;
};
typedef struct StructInfoNodo typeNode;
/* Struct to store pointers to firs & last element linked list */
struct structInfoLista {
typeNode *firstNode;
typeNode *lastNode;
int num_nodes;
};
typedef struct structInfoLista typeInfoList;
/* Initialitate frist & last elements linked list */
void initLinkedList (typeInfoList *list){
list->firstNode = NULL;
list->lastNode = NULL;
list->num_nodes= 0;
}
/* Insert First Element on the List (CreateList) */
int createList (typeInfoList * list, typeNet nodeinfo) {
typeNode *new_node;
if ((new_node = (typeNode *) malloc (sizeof (typeNode))) == NULL)
{
printf ("Error. Unable to create node");
return -1;
}
new_node->info.idCell=nodeinfo.idCell;
new_node->nextNode = NULL;
list->firstNode = new_node;
list->lastNode = new_node;
list->num_nodes;
return 0;
}
int main()
{
typeNet net;
typeInfoList *list;
// Get memory to store struct with pointers to first & last Nodes
if ((list = (typeInfoList *) malloc (sizeof (typeInfoList))) == NULL)
{
printf ("Error!! Unable to get memory");
exit (1);
}
//Create auxiliar list to store pointers to first & last nodes
initLinkedList (list);
// Sample data to add to first element of the list
net.idCell=5;
//Create initial linked list (first element)
createList (list, net);
}
this
typedef struct StructInfoNodo typeNode;
should be
typedef struct structInfoNodo typeNode;

Recursive aggregate type configured using many template parameters using std::index_sequence

There is a class template:
template<std::size_t ID, std::size_t T1, std::size_t T2, std::size_t T3>
class Feature { /* Implementation goes here */ };
All the instantiations of Feature<...> are 'collected' here:
template<typename FEATURE, typename... OTHERS>
class Features<FEATURE, OTHERS...> : public Features<OTHERS...> {
public:
/* Operations defined here */
private:
FEATURE m_feature;
};
All the features are created as follows:
using FeatureConfig = Features<Feature<0, 1, 2, 3>, Feature<1, 4, 5, 6>>;
FeatureConfig m_features;
So far so good. My task is to get rid of those hard coded values in there 1..3, 4..6 etc. The way to do so is to have generated header file which contains the configuration for all the features. Something like:
template<std::size_t> struct Config;
template<>
struct Config<0> {
static constexpr std::size_t t1 { 1 };
static constexpr std::size_t t2 { 2 };
static constexpr std::size_t t3 { 3 };
};
template<>
struct Config<1> {
static constexpr std::size_t t1 { 4 };
static constexpr std::size_t t2 { 5 };
static constexpr std::size_t t3 { 6 };
};
Then I need to change type definition of FeatureConfig somehow to use the specializations of FeatureConfig based on an index (0, 1, ...). My unsuccessfull try is:
template<std::size_t... INDEX_SEQUENCE>
using FeatureConfig = Features<Feature<INDEX_SEQUENCE, Config<INDEX_SEQUENCE>::t1, Config<INDEX_SEQUENCE>::t2, Config<INDEX_SEQUENCE>::t3>...>;
FeatureConfig<std::make_index_sequence<2>> m_features;
It seems I am somehow mixing type and value...
Many thanks in advance to anyone willing to help me fix the incorrect code in my last listing up there.
Cheers Martin
If I understand correctly what do you want...
I propose the declaration (no definition required because is used only inside a decltype()) of the following function
template <std::size_t ... Is>
auto getFeaturesType (std::index_sequence<Is...>)
-> Features<Feature<Is, Config<Is>::t1, Config<Is>::t2, Config<Is>::t3>...>;
Now you can define FeatureConfig simply as follows
template <std::size_t N>
using FeatureConfig
= decltype(getFeaturesType(std::make_index_sequence<N>{}));
The following is a full compiling (simplified) example
#include <type_traits>
#include <utility>
template <std::size_t, std::size_t, std::size_t, std::size_t>
struct Feature { };
template <typename...>
struct Features
{ };
template <typename F, typename... Os>
struct Features<F, Os...> : public Features<Os...>
{ F m_feature; };
template <std::size_t N>
struct Config
{
static constexpr std::size_t t1 { N*3u };
static constexpr std::size_t t2 { 1u + N*3u };
static constexpr std::size_t t3 { 2u + N*3u };
};
template <std::size_t ... Is>
auto getFeaturesType (std::index_sequence<Is...>)
-> Features<Feature<Is, Config<Is>::t1, Config<Is>::t2, Config<Is>::t3>...>;
template <std::size_t N>
using FeatureConfig
= decltype(getFeaturesType(std::make_index_sequence<N>{}));
int main ()
{
using T1 = FeatureConfig<2u>;
using T2 = Features<Feature<0u, 0u, 1u, 2u>, Feature<1u, 3u, 4u, 5u>>;
static_assert( std::is_same<T1, T2>::value, "!" );
}
If I understand correctly how do you use Config (if t1 is ever N*3u, if if t2 is ever 1u+N*3u and if t3 is ever 2u+N*3u), you can avoid Config at all and write getFeaturesType as follows
template <std::size_t ... Is>
auto getFeaturesType (std::index_sequence<Is...>)
-> Features<Feature<Is, Is*3u, Is*3u+1u, Is*3u+2u>...>;

Variadic Dispatch Function

I have an interface wherein the types of the parameters mostly encode their own meanings. I have a function that takes one of these parameters. I'm trying to make a function that takes a set of these parameters and performs the function on each one in order.
#include <iostream>
#include <vector>
enum param_type{typeA,typeB};
template <param_type PT> struct Container{
int value;
Container(int v):value(v){}
};
int f(Container<typeA> param){
std::cout<<"Got typeA with value "<<param.value<<std::endl;
return param.value;
}
int f(Container<typeB> param){
std::cout<<"Got typeB with value "<<param.value<<std::endl;
return param.value;
}
My current solution uses a recursive variadic template to delegate the work.
void g(){}
template <typename T,typename...R>
void g(T param,R...rest){
f(param);
g(rest...);
}
I would like to use a packed parameter expansion, but I can't seem to get that to work without also using the return values. (In my particular case the functions are void.)
template <typename...T> // TODO: Use concepts once they exist.
void h(T... params){
// f(params);...
// f(params)...; // Fail to compile.
// {f(params)...};
std::vector<int> v={f(params)...}; // Works
}
Example usage
int main(){
auto a=Container<typeA>(5);
auto b=Container<typeB>(10);
g(a,b);
h(a,b);
return 0;
}
Is there an elegant syntax for this expansion in C++?
In C++17: use a fold expression with the comma operator.
template <typename... Args>
void g(Args... args)
{
((void)f(args), ...);
}
Before C++17: comma with 0 and then expand into the braced initializer list of an int array. The extra 0 is there to ensure that a zero-sized array is not created.
template <typename... Args>
void g(Args... args)
{
int arr[] {0, ((void)f(args), 0)...};
(void)arr; // suppress unused variable warning
}
In both cases, the function call expression is cast to void to avoid accidentally invoking a user-defined operator,.

Storing multiple types into class member container

I was reading this Q/A here and as my question is similar but different I would like to know how to do the following:
Let's say I have a basic non template non inherited class called Storage.
class Storage {};
I would like for this class to have a single container (unordered multimap) is where I'm leaning towards... That will hold a std::string for a name id to a variable type T. The class itself will not be template. However a member function to add in elements would be. A member function to add might look like this:
template<T>
void addElement( const std::string& name, T& t );
This function will then populate the unorderd multimap. However each time this function is called each type could be different. So my map would look something like:
"Hotdogs", 8 // here 8 is int
"Price", 4.85f // here 4.8f is float.
How would I declare such an unorderd multimap using templates, variadic parameters, maybe even tuple, any or variant... without the class itself being a template? I prefer not to use boost or other libraries other than the standard.
I tried something like this:
class Storage {
private:
template<class T>
typedef std::unorderd_multimap<std::string, T> DataTypes;
template<class... T>
typedef std::unordered_multimap<std::vector<std::string>, std::tuple<T...>> DataTypes;
};
But I can not seem to get the typedefs correct so that I can declare them like this:
{
DataTypes mDataTypes;
}
You tagged C++17, so you could use std::any (or std::variant if the T type can be a limited and know set of types`).
To store the values is simple.
#include <any>
#include <unordered_map>
class Storage
{
private:
using DataTypes = std::unordered_multimap<std::string, std::any>;
DataTypes mDataTypes;
public:
template <typename T>
void addElement (std::string const & name, T && t)
{ mDataTypes.emplace(name, std::forward<T>(t)); }
};
int main()
{
Storage s;
s.addElement("Hotdogs", 8);
s.addElement("Price", 4.85f);
// but how extract the values ?
}
But the problem is that now you have a element with "Hotdogs" and "Price" keys in the map, but you have no info about the type of the value.
So you have to save, in some way, a info about the type of th value (transform the value in a std::pair with some id-type and the std::any?) to extract it when you need it.
I've done something along those lines, the actual solution is very specific to your problem.
That being said, I'm doing this on a vector, but the principle applies to maps, too.
If you're not building an API and hence know all classes that will be involved you could use std::variant something along the lines of this:
#include <variant>
#include <vector>
#include <iostream>
struct ex1 {};
struct ex2 {};
using storage_t = std::variant<ex1, ex2>;
struct unspecific_operation {
void operator()(ex1 arg) { std::cout << "got ex1\n";}
void operator()(ex2 arg) { std::cout << "got ex2\n";}
};
int main() {
auto storage = std::vector<storage_t>{};
storage.push_back(ex1{});
storage.push_back(ex2{});
auto op = unspecific_operation{};
for(const auto& content : storage) {
std::visit(op, content);
}
return 0;
}
which will output:
got ex1
got ex2
If I remember correctly, using std::any will enable RTTI, which can get quite expensive; might be wrong tho.
If you provide more specifics about what you actually want to do with it, I can give you a more specific solution.
for an example with the unordered map:
#include <variant>
#include <unordered_map>
#include <string>
#include <iostream>
struct ex1 {};
struct ex2 {};
using storage_t = std::variant<ex1, ex2>;
struct unspecific_operation {
void operator()(ex1 arg) { std::cout << "got ex1\n";}
void operator()(ex2 arg) { std::cout << "got ex2\n";}
};
class Storage {
private:
using map_t = std::unordered_multimap<std::string, storage_t>;
map_t data;
public:
Storage() : data{map_t{}}
{}
void addElement(std::string name, storage_t elem) {
data.insert(std::make_pair(name, elem));
}
void doSomething() {
auto op = unspecific_operation{};
for(const auto& content : data) {
std::visit(op, content.second);
}
}
};
int main() {
auto storage = Storage{};
storage.addElement("elem1", ex1{});
storage.addElement("elem2", ex2{});
storage.addElement("elem3", ex1{});
storage.doSomething();
return 0;
}

boost python overload operator ()

I would like to bind the operator() using Boost::Python but I don't really see how to do this. Consider the example:
C++:
class Queuer
{
public:
void Queuer::operator()(const qfc::Queue & iq, const qfc::Message & im) const;
void Queuer::operator()(const qfc::Agent & ia, const qfc::Message & im) const;
// some other overloaded operator() methods
};
So in a Python script, after importing the module I'm using (called qfc), I would like to do:
Python:
>>> queuer = qfc.Queuer()
// instantiating a Message an Agent and a Queue object
>>> queuer(queue,message)
>>> queuer(agent,message)
>>> ...
Would you have any idea on how to do it? maybe with boost::python call<>?
Thank you,
Kevin
When exposing the Queuer class, define a __call__ method for each Queuer::operator() member function. Boost.Python will handle the appropriate dispatching based on types. The only complexity is introduced with pointer-to-member-function syntax, as the caller is required to disambiguate &Queuer::operator().
Additionally, when attempting to pass derived classes in Python to a C++ function with a parameter of the Base class, then some additional information needs to be exposed to Boost.Python:
The base C++ class needs to be exposed with class_. For example, class_<BaseType>("Base").
The derived class needs to explicitly list its base classes when being exposed with bases_. For example, class_<DerivedType, bases<BaseType> >("Derived"). With this information, Boost.Python can do proper casting while dispatching.
Here is a complete example:
#include <iostream>
#include <boost/python.hpp>
// Mockup classes.
struct AgentBase {};
struct MessageBase {};
struct QueueBase {};
struct SpamBase {};
struct Agent: AgentBase {};
struct Message: MessageBase {};
struct Queue: QueueBase {};
struct Spam: SpamBase {};
// Class with overloaded operator().
class Queuer
{
public:
void operator()(const AgentBase&, const MessageBase&) const
{
std::cout << "Queuer::operator() with Agent." << std::endl;
}
void operator()(const QueueBase&, const MessageBase&) const
{
std::cout << "Queuer::operator() with Queue." << std::endl;
}
void operator()(const SpamBase&, const MessageBase&) const
{
std::cout << "Queuer::operator() with Spam." << std::endl;
}
};
/// Depending on the overlaod signatures, helper types may make the
/// code slightly more readable by reducing pointer-to-member-function syntax.
template <typename A1>
struct queuer_overload
{
typedef void (Queuer::*type)(const A1&, const MessageBase&) const;
static type get(type fn) { return fn; }
};
BOOST_PYTHON_MODULE(example)
{
namespace python = boost::python;
// Expose only the base class types. Do not allow the classes to be
// directly initialized in Python.
python::class_<AgentBase >("AgentBase", python::no_init);
python::class_<MessageBase>("MessageBase", python::no_init);
python::class_<QueueBase >("QueueBase", python::no_init);
python::class_<SpamBase >("SpamBase", python::no_init);
// Expose the user types. These classes inerit from their respective
// base classes.
python::class_<Agent, python::bases<AgentBase> >("Agent");
python::class_<Message, python::bases<MessageBase> >("Message");
python::class_<Queue, python::bases<QueueBase> >("Queue");
python::class_<Spam, python::bases<SpamBase> >("Spam");
// Disambiguate via a varaible.
queuer_overload<AgentBase>::type queuer_op_agent = &Queuer::operator();
python::class_<Queuer>("Queuer")
// Disambiguate via a variable.
.def("__call__", queuer_op_agent)
// Disambiguate via a helper type.
.def("__call__", queuer_overload<QueueBase>::get(&Queuer::operator()))
// Disambiguate via explicit cast.
.def("__call__",
static_cast<void (Queuer::*)(const SpamBase&,
const MessageBase&) const>(
&Queuer::operator()))
;
}
And its usage:
>>> import example
>>> queuer = example.Queuer()
>>> queuer(example.Agent(), example.Message())
Queuer::operator() with Agent.
>>> queuer(example.Queue(), example.Message())
Queuer::operator() with Queue.
>>> queuer(example.Spam(), example.Message())
Queuer::operator() with Spam.
Thanks for your help.
Actually I've already tested the static cast solution. In reality, I need to pass a qfc::lqs::Message or qfc::lqs::Agent or qfc::lqs::Spam when invoking queuer(). qfc::lqs::Message for example, as for qfc::lqs::Agent inherit from qfc::Message and qfc::Agent respectively.
So can I "cast" qfc::lqs::Message, qfc::lqs::Agent and qfc::lqs::Spam to qfc::Message, qfc::Agent and qfc::Spam when invoking the operator() so that the signature corresponds to operator() ?
This to avoid the error shown below:
error: invalid static_cast from type '<unresolved overloaded function type>' to type 'void (qfc::lqs::Queuer::*)(const qfc::lqs::Queue&, const qfc::lqs::Message&)const'

Resources