admin管理员组文章数量:1192124
Lately I have been an avid user of implementation visitor pattern into my code. I was used to the classic way of implementation but since we have the std::variant functionality from c++ 17. I tend to use std::visit together with variant inorder to implement visitor pattern. However there are limitations that I have found using the std::visit functionality.
My understanding of std::visit is that it takes in a lambda or a struct/class implementing each individual item from the list of variant types. However my observation is that when I implement a class with hierarchy and the parent class implements the operator() overloads and children object calls it. It works!. However if I implement additional operator() overloads in the child class which has no relation to variant types. The code breaks and throws an error telling std::visit requires the visitor to be exhaustive.
`
#include <iostream>
#include <variant>
#include <string>
#include <vector>
using TYPE = std::variant<int, double, float, std::string, std::monostate>;
class parentVisitor {
public:
parentVisitor() = default;
std::string operator()(const int value) const {return std::to_string(value);}
std::string operator()(const double value) const {return std::to_string(value);}
std::string operator()(const float value) const {return std::to_string(value);}
std::string operator()(std::string value) const {return value;}
std::string operator()(std::monostate) const {return "";}
};
class childVisitor : public parentVisitor {
private:
TYPE m_value;
public:
// The below line creates the error!
void operator()(std::vector<int> value) const {}
explicit childVisitor(TYPE value) : m_value(std::move(value)) {};
void printValue() {
const std::string text = std::visit(*this, m_value);
std::cout << text << std::endl;
}
};
int main() {
std::string text = "CPP";
childVisitor visitor(text);
visitor.printValue();
return 0;
}
Error Message is shown below:
error: static assertion failed due to requirement 'is_invocable_v<childVisitor &, int &>': `std::visit` requires the visitor to be exhaustive.
611 | static_assert(is_invocable_v<_Visitor, _Values...>, "`std::visit` requires the visitor to be exhaustive.");
I think the intention of std::visit is use lambda function or a structure/class with a hierarchy implementing unique operator() overloads.
But let's try abusing the std::visit by implementing a function in parent class which could be called from the child class which will enforce the visitor pattern.
`
#include <iostream>
#include <variant>
#include <string>
#include <vector>
using TYPE = std::variant<int, double, float, std::string, std::monostate>;
class parentVisitor {
public:
parentVisitor() = default;
std::string operator()(const int value) const {return std::to_string(value);}
std::string operator()(const double value) const {return std::to_string(value);}
std::string operator()(const float value) const {return std::to_string(value);}
std::string operator()(std::string value) const {return value;}
std::string operator()(std::monostate) const {return "";}
std::string visit_parent(TYPE type) {
return std::visit(*this, type);
}
};
class childVisitor : public parentVisitor {
private:
TYPE m_value;
public:
// The below line creates the error!
void operator()(std::vector<int> value) const {}
explicit childVisitor(TYPE value) : m_value(std::move(value)) {};
void printValue() {
//const std::string text = std::visit(*this, m_value);
std::string text = visit_parent(m_value);
std::cout << text << std::endl;
}
};
int main() {
std::string text = "CPP";
childVisitor visitor(text);
visitor.printValue();
return 0;
}
Now this works because the parent class has clear implementation of operator() overloads.
Let me know it makes sense and is there any other way of implementing visitor functionality from a hierarchy.
Lately I have been an avid user of implementation visitor pattern into my code. I was used to the classic way of implementation but since we have the std::variant functionality from c++ 17. I tend to use std::visit together with variant inorder to implement visitor pattern. However there are limitations that I have found using the std::visit functionality.
My understanding of std::visit is that it takes in a lambda or a struct/class implementing each individual item from the list of variant types. However my observation is that when I implement a class with hierarchy and the parent class implements the operator() overloads and children object calls it. It works!. However if I implement additional operator() overloads in the child class which has no relation to variant types. The code breaks and throws an error telling std::visit requires the visitor to be exhaustive.
`
#include <iostream>
#include <variant>
#include <string>
#include <vector>
using TYPE = std::variant<int, double, float, std::string, std::monostate>;
class parentVisitor {
public:
parentVisitor() = default;
std::string operator()(const int value) const {return std::to_string(value);}
std::string operator()(const double value) const {return std::to_string(value);}
std::string operator()(const float value) const {return std::to_string(value);}
std::string operator()(std::string value) const {return value;}
std::string operator()(std::monostate) const {return "";}
};
class childVisitor : public parentVisitor {
private:
TYPE m_value;
public:
// The below line creates the error!
void operator()(std::vector<int> value) const {}
explicit childVisitor(TYPE value) : m_value(std::move(value)) {};
void printValue() {
const std::string text = std::visit(*this, m_value);
std::cout << text << std::endl;
}
};
int main() {
std::string text = "CPP";
childVisitor visitor(text);
visitor.printValue();
return 0;
}
Error Message is shown below:
error: static assertion failed due to requirement 'is_invocable_v<childVisitor &, int &>': `std::visit` requires the visitor to be exhaustive.
611 | static_assert(is_invocable_v<_Visitor, _Values...>, "`std::visit` requires the visitor to be exhaustive.");
I think the intention of std::visit is use lambda function or a structure/class with a hierarchy implementing unique operator() overloads.
But let's try abusing the std::visit by implementing a function in parent class which could be called from the child class which will enforce the visitor pattern.
`
#include <iostream>
#include <variant>
#include <string>
#include <vector>
using TYPE = std::variant<int, double, float, std::string, std::monostate>;
class parentVisitor {
public:
parentVisitor() = default;
std::string operator()(const int value) const {return std::to_string(value);}
std::string operator()(const double value) const {return std::to_string(value);}
std::string operator()(const float value) const {return std::to_string(value);}
std::string operator()(std::string value) const {return value;}
std::string operator()(std::monostate) const {return "";}
std::string visit_parent(TYPE type) {
return std::visit(*this, type);
}
};
class childVisitor : public parentVisitor {
private:
TYPE m_value;
public:
// The below line creates the error!
void operator()(std::vector<int> value) const {}
explicit childVisitor(TYPE value) : m_value(std::move(value)) {};
void printValue() {
//const std::string text = std::visit(*this, m_value);
std::string text = visit_parent(m_value);
std::cout << text << std::endl;
}
};
int main() {
std::string text = "CPP";
childVisitor visitor(text);
visitor.printValue();
return 0;
}
Now this works because the parent class has clear implementation of operator() overloads.
Let me know it makes sense and is there any other way of implementing visitor functionality from a hierarchy.
Share Improve this question asked Jan 24 at 2:36 Sukrit GhoraiSukrit Ghorai 111 bronze badge 1 |1 Answer
Reset to default 3This is a normal feature of inheritance in C++. Defining a method in a derived class hides the method of the same name from the parent class. For instance, the following will fail to compile for the same reason as your first program:
struct Parent
{
void foo(int) {}
};
struct Child : Parent
{
void foo(std::string) {}
};
int main()
{
Child c;
c.foo(42);
}
Demo
You can bring the parent class's function into the child class's scope with the using
keyword:
struct Parent
{
void foo(int) {}
};
struct Child : Parent
{
using Parent::foo; // <--- Add this
void foo(std::string) {}
};
int main()
{
Child c;
c.foo(42);
}
Demo
You can do the same thing in your childVisitor
by adding using parentVisitor::operator()
本文标签: cUsing and abusing stdvisitStack Overflow
版权声明:本文标题:c++ - Using and abusing std::visit - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1738451747a2087525.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
using parentVisitor::operator();
to yourchildVisitor
for the first example. – Stephen Newell Commented Jan 24 at 2:46