Why it is okay when define op_and* operator&(data& left, data& right) in op.h
/* data.h */
#ifndef _DATA_H
#define _DATA_H
#include <string>
#include <utility>
#include "node.h"
#include "op.h"
struct data: node{
    std::string name;
    int width;
};
#endif //_DATA_H
/* op.h */
#ifndef _OP_H
#define _OP_H
#include <string>
#include <utility>
#include "node.h"
#include "data.h"
struct op: node {
    const std::string symbol;
    explicit op(data& left, data& right, std::string symbol):
    node(left, NODES::EMPTY, right), symbol(std::move(symbol)){}
};
struct op_and: op{
    explicit op_and(data& left, data& right):
    op(left, right, "&"){}
};
op_and* operator&(data& left, data& right){
    return new op_and(left, right); // it is okay here
}
#endif //_OP_H
But when define it data.h, IDE hints No matching constructor for initialization of "op_and"?
/* data.h */
#ifndef _DATA_H
#define _DATA_H
#include <string>
#include <utility>
#include "node.h"
#include "op.h"
struct data: node{
    std::string name;
    int width;
};
op_and* operator&(data& left, data& right){
    return new op_and(left, right); // here is error, cannot find op_and(data&, data&)
}
#endif //_DATA_H
This does look like a Circular dependency problem. I made a mistake. When I tried to include op.h in data.h, I get something like:
#ifndef _DATA_H
#define _DATA_H
#include <string>
#include <utility>
#include "node.h"
#ifndef _OP_H
#define _OP_H
/* including "op.h" starts */
#include <string>
#include <utility>
#include "node.h"
#include "data.h" // this will introduce nothing because _DATA_H is already defined
struct op: node {
public:
    const std::string symbol;
    symbol(std::move(symbol)){}
    explicit op(data& left, data& right, std::string symbol): // symbol "data" has not been declared yet
            node(left, NODES::EMPTY, right), symbol(std::move(symbol)){}
};
struct op_and: op{
public:
    explicit op_and(data& left, data& right): // symbol "data" has not been declared yet
            op(left, right, "&"){}
};
#endif //_OP_H
/* including "op.h" ends */
struct data: node{
    std::string name;
    int width;
};
op_and* operator&(data& left, data& right){
    return new op_and(left, right); // error
}
#endif //_DATA_H
Now, definitions of struct op, struct op_and, and method operator& are in-valid since symbol data has not been declared.
So, if I put #include "op.h" after the definition of struct node, things work fine.
#ifndef _DATA_H
#define _DATA_H
#include <string>
#include <utility>
#include "node.h"
struct data: node{
    std::string name;
    int width;
};
#include "op.h"
op_and* operator&(data& left, data& right){
    return new op_and(left, right);
}
#endif //_DATA_H
 
    