Let's say I'm trying to create a Combine class that will be derived from the given base classes.
template<typename ...Bases>
class Combine : public Bases... {};
And this works fine. For example, if I have class Foo and class Bar then class Combine<Foo, Bar> will implement all the methods from Foo and Bar. At least I thought so until I tried this:
struct ContainerProvider {
std::vector<int> container{1, 2, 3};
};
struct ConstGetter : public virtual ContainerProvider {
[[nodiscard]] const int &get(int index) const {
return container[index];
}
};
struct MutableGetter : public virtual ContainerProvider {
int &get(int index) {
return container[index];
}
};
template<typename ...Bases>
class Combine : public Bases... {};
int main() {
Combine<ConstGetter, MutableGetter> container;
container.get(1); // Member 'get' found in multiple base classes of different types
}
In normal situations, I would just use using Super::method;, but here I don't know the names of derived methods. In a perfect world, I could use something like this:
template<typename ...Bases>
class Combine : public Bases... {
using Bases::* ...;
};
But C++ does not allow this.
Is it possible to implement my Combine class somehow? I'm pretty sure the compiler can get all the information to resolve this edge case, but I have no idea how to provide it to make it work.
Curious problem since get() defined only in one class would work perfectly, but in two? Error? I was curious if there might be a core language defect since this problem seems solvable by the compiler, but I didn't see any (http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html).
The ideal solution would probably be for MutableGetter to inherit from ConstGetter since, logically, a getter that allows mutation should also allow grabbing non-mutable versions.
struct MutableGetter : public ConstGetter {
using ConstGetter::get;
int &get(int index) {
return container[index];
}
};
Here's the closest I could get:
#include <iostream>
#include <vector>
struct ContainerProvider {
std::vector<int> container{1, 2, 3};
};
struct ConstGetter : public virtual ContainerProvider {
[[nodiscard]] const int &get(int index) const {
std::cout << "CONST" << std::endl;
return container[index];
}
};
struct MutableGetter : public virtual ContainerProvider {
int &get(int index) {
std::cout << "NON-CONST" << std::endl;
return container[index];
}
};
template <typename... Bases>
class Combine;
template <typename B1, typename B2, typename... Bases>
struct Combine<B1, B2, Bases...> : public B1, public Combine<B2, Bases...> {
using B1::get;
using Combine<B2, Bases...>::get;
};
template<typename B>
struct Combine<B> : B {
using B::get;
};
int main() {
Combine<ConstGetter, MutableGetter> container;
std::cout << container.get(0) << std::endl; // non-const
const auto &const_container = container;
std::cout << const_container.get(0) << std::endl; // const
}
It really sucks for the Combine to have to know what member functions its parents expose, though. I found one partial solution if you're willing to drop the idea of member functions and occasionally do a cast...: Use friend functions
#include <iostream>
#include <vector>
struct ContainerProvider {
std::vector<int> container{1, 2, 3};
};
class ConstGetter : public virtual ContainerProvider {
[[nodiscard]] const int &get(int index) const {
std::cout << "CONST" << std::endl;
return container[index];
}
friend [[nodiscard]] const int& get(const ConstGetter &self, int i) { return self.get(i); }
};
class MutableGetter : public virtual ContainerProvider {
int &get(int index) {
std::cout << "NON-CONST" << std::endl;
return container[index];
}
friend [[nodiscard]] const int &get(MutableGetter &self, int i) {
return self.get(i);
}
};
template <typename... Bases>
class Combine : public Bases... {};
int main() {
Combine<ConstGetter, MutableGetter> container;
std::cout << get((MutableGetter&)container, 0) << std::endl;
const auto &const_container = container;
std::cout << get(const_container, 0) << std::endl;
}
I imagine that renaming ConstGetter::get() to ConstGetter::const_get is not an option? However, this compiles: container.ConstGetter::get(); container.MutableGetter::get();, check it here
As of why overload resolution doesn't work across classes, you could check
this old post
and the answer of this question.
Related
I would like to construct a robot with or without a tool, a mobile base, and other parts. As I want to automatize the configuration of the parts, I have a class Robot with the parts as template arguments
For instance, in the code below, the code will build as long as we use tools that have the same constructor signature as ToolInterface. It does build with a Screwdriver but does not with a Gripper.
#include <iostream>
#include <string>
class BaseRobot
{
public:
BaseRobot(){};
};
class ToolInterface
{
public:
ToolInterface(BaseRobot* _base, std::string _name):name{_name}{/*register _base*/};
std::string name;
bool param_1;
char param_2;
};
template<class T, class... Args>
constexpr T* construct(Args... args)
{
if constexpr (std::is_same<T, nullptr_t>::value)
{
return nullptr;
}
else
{
return new T(args...);
}
};
template<class Tool>
class Robot : public BaseRobot
{
protected:
Tool* tool;
public:
Robot():tool(construct<Tool>(this, "tool")){ // <--- here is my problem !!
if constexpr (! std::is_same<Tool, nullptr_t>::value)
{
//do stuff on/with tool->param_1, tool->param_2, ...
std::cout << "tool configured" << std::endl;
}
else
std::cout << "no tool" << std::endl;
};
};
class Screwdriver: public ToolInterface
{
public:
Screwdriver(BaseRobot* _base, std::string _name):ToolInterface(_base, _name){};
};
class Gripper: public ToolInterface
{
public:
Gripper(BaseRobot* _base, std::string _name, bool _reversed):
ToolInterface(_base, _name)
,reversed{_reversed}{};
bool reversed;
};
int main()
{
Robot<Screwdriver> robot_screwdriver;
Robot<nullptr_t> robot_null;
//Robot<Gripper> robot_gripper; //does not build
return 0;
}
Here are some ideas :
using a ToolConfig struct that is passed as an argument of Tools. If a tool requires more arguments, one should subclass ToolConfig and cast it into the tool constructor (see below): damn, that looks cumbersome and ugly!
enforce inherited ToolInterface classes Ctor signature: some tools must have a different Ctor signature
using a variadic template to pass args into the template: not reasonable because, in the end, I want something like template<class Tool1, class Tool2, class MobileBase, class Camera> class Robot
solution 1 would look like
struct ToolConfig
{
std::string name;
};
struct GripperConfig : public ToolConfig
{
bool reversed;
};
class Gripper : public ToolInterface
{
public:
Gripper(ToolConfig& _config):
ToolInterface(_config)
,reversed{static_cast<GripperConfig&>(_config).reversed}{};
bool reversed;
};
Do you have a magic pattern to solve my problem? Is my pattern wrong?
You could also use tuple instead of struct, not ideal but this works as well:
#include <iostream>
#include <string>
#include <tuple>
class BaseRobot
{
public:
BaseRobot() {};
};
class ToolInterface
{
public:
ToolInterface(std::string _name) :name{ _name } {/*register _base*/ };
std::string name;
bool param_1;
char param_2;
};
template <typename T, typename ... Types, std::size_t ... Indices>
constexpr T* apply_impl(const std::tuple<Types...>& tuple, std::index_sequence<Indices...>)
{
return new T(std::get<Indices>(tuple)...);
}
template <typename T, typename ... Types>
constexpr T* apply(const std::tuple<Types...>& tuple)
{
return apply_impl<T>(tuple, std::index_sequence_for<Types...>());
}
template<class T, class... Args>
constexpr T* construct(std::tuple<Args...> args)
{
if constexpr (std::is_same<T, nullptr_t>::value)
{
return nullptr;
}
else
{
return apply<T>(args);
}
}
template<class Tool>
class Robot : public BaseRobot
{
protected:
Tool* tool;
public:
template<class ...Args1> //, class ...Args2>
Robot(std::tuple<Args1...> p1): // , std::tuple<Args2...> p2):
tool(construct<Tool>(p1))
{ // <--- here is my problem !!
if constexpr (!std::is_same<Tool, nullptr_t>::value)
{
//do stuff on/with tool->param_1, tool->param_2, ...
std::cout << "tool configured" << std::endl;
}
else
std::cout << "no tool" << std::endl;
};
};
class Screwdriver : public ToolInterface
{
public:
Screwdriver(std::string _name) :ToolInterface(_name) {};
};
class Gripper : public ToolInterface
{
public:
Gripper(std::string _name, bool _reversed) :
ToolInterface(_name)
, reversed{ _reversed }{};
bool reversed;
};
int main()
{
using p1 = std::tuple<std::string>;
Robot<Screwdriver> robot_screwdriver(p1{"sdvr"});
return 0;
}
Could be improved I agree.
You could pass factory lambdas that generate your tools in the initializer.
template<typename Func>
Robot(Func f):tool(f(this, "tool")){ // <--- here is my problem !!
if constexpr (! std::is_same<Tool, std::nullptr_t>::value)
{
//do stuff on/with tool->param_1, tool->param_2, ...
std::cout << "tool configured" << std::endl;
}
else
std::cout << "no tool" << std::endl;
};
The call site would look like this:
Robot<Screwdriver> robot_screwdriver([](auto... args){ return new Screwdriver(args...); });
Robot<std::nullptr_t> robot_null([](auto...){ return nullptr; });
Robot<Gripper> robot_gripper([](auto... args){ return new Gripper(args..., true); });
Not exactly beautiful, but it works.
See here for a full example. Does this solve your problem?
If you can use c++17, you can add a class template deduction guide to reduce some of the redundancy at the call site.
Assume you have a std::tuple with a common base class:
class MyBase { public: virtual int getVal() = 0; };
class MyFoo1: public MyBase { public: int getVal() override { return 101; } };
class MyFoo2: public MyBase { public: int getVal() override { return 202; } };
using MyTuple = std::tuple<MyFoo1, MyFoo2, MyFoo1>;
How do you iterate over the elements of the tuple at runtime? The usual answer is that you can't because they all have different types, but here I'm happy for a static type of MyBase*. I'm hoping for code like this:
MyTuple t;
for (Base* b : iterate_tuple<MyBase>(t)) {
std::cout << "Got " << b->getVal() << "\n";
}
There are a lot of helpful ideas over at How can you iterate over the elements of an std::tuple?, but they all include the code to run at each iteration in the fiddly template code, whereas I'd like all the fiddly template code bundled into the hypothetical iterate_tuple function so my code is just a normal for loop.
Here's a little wrapper function that gets the tuple value by index, specified at runtime, which does a linear search for the right index by recursively calling itself with a different template parameter. You specify its return type as a template parameter, and the value gets implicitly converted to it.
template <class BaseT, class TupleT, size_t currentIndex = 0>
BaseT* getBasePtr(TupleT& t, size_t desiredIndex) {
if constexpr (currentIndex >= std::tuple_size<TupleT>::value) {
return nullptr;
}
else {
if (desiredIndex == currentIndex) {
return &std::get<currentIndex>(t);
}
else {
return getBasePtr<BaseT, TupleT, currentIndex + 1>(t, desiredIndex);
}
}
}
You can then use it in a loop over the indices of the tuple:
for (size_t i = 0; i < std::tuple_size<MyTuple>::value; ++i) {
MyBase* b = getBasePtr<MyBase>(t, i);
std::cout << "At " << i << " got " << b->getVal() << "\n";
}
It's not quite as neat as a range-based for loop but it's still pretty straightforward to use. (You could wrap it in an iterator class that would support range-based loops but I don't really think it's worth the effort.)
As mentioned and suggested in the question linked to using std::apply is a good way to get each individual element of the tuple.
Making a small helper function to wrap the forwarding of each tuple element makes it easy to use.
It's not the specific for-loop syntax you asked for, but it's as easy to follow if you ask me.
#include <tuple>
#include <utility>
#include <iostream>
class MyBase { public: virtual int getVal() = 0; };
class MyFoo1: public MyBase { public: int getVal() override { return 101; } };
class MyFoo2: public MyBase { public: int getVal() override { return 202; } };
using MyTuple = std::tuple<MyFoo1, MyFoo2, MyFoo1>;
template <typename Tuple, typename Callable>
void iterate_tuple(Tuple&& t, Callable c) {
std::apply([&](auto&&... args){ (c(args), ...); }, t);
}
int main() {
MyTuple t;
iterate_tuple(t, [](auto& arg) {
std::cout << "Got " << arg.getVal() << "\n";
});
iterate_tuple(t, [](MyBase& arg) {
std::cout << "Got " << arg.getVal() << "\n";
});
}
We can get the exact type by using auto or use the common base type.
As Sam suggests in the comments, it's quite simple to create an array from a tuple.
template<typename Base, typename Tuple, size_t... Is>
std::array<Base *, std::tuple_size_v<Tuple>> iterate_tuple_impl(Tuple& tuple, std::index_sequence<Is...>)
{
return { std::addressof(std::get<Is>(tuple))... };
}
template<typename Base, typename Tuple>
std::array<Base *, std::tuple_size_v<Tuple>> iterate_tuple(Tuple& tuple)
{
return iterate_tuple_impl(tuple, std::make_index_sequence<std::tuple_size_v<Tuple>>{});
}
If you have inheritance, why not to do without tuple and use inheritance capabilities like this:
#include <iostream>
#include <vector>
class MyBase { public: virtual int getVal() = 0; };
class MyFoo1 : public MyBase { public: int getVal() override { return 101; } };
class MyFoo2 : public MyBase { public: int getVal() override { return 202; } };
int main() {
std::vector<std::unique_ptr<MyBase>> base;
base.emplace_back(new MyFoo1);
base.emplace_back(new MyFoo2);
for (auto && derived : base) {
std::cout << derived->getVal() << std::endl;
}
}
I would directly use std::apply, but you can create array of Base*:
template <typename Base, typename Tuple>
std::array<Base*, std::tuple_size<Tuple>> toPtrArray(Tuple& tuple)
{
return std::apply([](auto& ... args){ return std::array<Base*, std::tuple_size<Tuple>>{{&args}}; }, tuple);
}
And then
MyTuple t;
for (Base* b : toPtrArray<MyBase>(t)) {
std::cout << "Got " << b->getVal() << "\n";
}
Note:
In the explanation and my example, I'm using the eigen library. However, my question can probably be generalised and understood by people not familiar with that library, e.g. by replacing the ConstColXpr with std::string_view and the Vector with a std::string.
Question:
I want to create an interface using CRTP, with two classes inheriting from it which differ in the following way when callling certain member functions:
The first class returns a view of a data member (an Eigen::Matrix<...>::ConstColXpr)
The second class does not have this data member. Instead, the appropriate values are calculated when the function is called and then returned (as an Eigen::Vector<...>)
Both return types have the same dimensions (e.g. a 2x1 column vector) and the same interface, i.e. can be interacted with in the exact same way. That's why I believe it is reasonable to define the function as part of the interface.
However, I don't know how to properly define/restrict the return type in the base class/interface. auto compiles and executes fine, but doesn't tell the user anything about what to expect.
Is it possible to define the interface in a clearer way? I tried using std::invoke_result with the implementation function, but then I'd have to include the inheriting types before the interface, which is quite backwards. And it's not much better than auto, as the actual type still has to be looked up in the implementation.
A nice answer would be a common Eigen type, where the dimensions are clear. However, I don't want calls to the interface function to require template parameters (which I'd have to do with Eigen::MatrixBase), because there's already code depending on the interface.
Another nice answer would be some construct that allows two different return types, but without having to know the full derived type. But all answers and also other feedback are welcome!
Here's the code illustrating the issue:
#include <Eigen/Dense>
#include <type_traits>
#include <utility>
#include <iostream>
template<typename T>
class Base
{
public:
auto myFunc(int) const;
protected:
Base();
};
template<typename T>
Base<T>::Base() {
/* make sure the function is actually implemented, otherwise generate a
* useful error message */
static_assert( std::is_member_function_pointer_v<decltype(&T::myFuncImp)> );
}
template<typename T>
auto Base<T>::myFunc(int i) const {
return static_cast<const T&>(*this).myFuncImp(i);
}
using Matrix2Xd = Eigen::Matrix<double,2,Eigen::Dynamic>;
class Derived1 : public Base<Derived1>
{
private:
Matrix2Xd m_data;
public:
Derived1( Matrix2Xd&& );
private:
auto myFuncImp(int) const -> Matrix2Xd::ConstColXpr;
friend Base;
};
Derived1::Derived1( Matrix2Xd&& data ) :
m_data {data}
{}
auto Derived1::myFuncImp(int i) const -> Matrix2Xd::ConstColXpr {
return m_data.col(i);
}
class Derived2 : public Base<Derived2>
{
private:
auto myFuncImp(int) const -> Eigen::Vector2d;
friend Base;
};
auto Derived2::myFuncImp(int i) const -> Eigen::Vector2d {
return Eigen::Vector2d { 2*i, 3*i };
}
int main(){
Matrix2Xd m (2, 3);
m <<
0, 2, 4,
1, 3, 5;
Derived1 d1 { std::move(m) };
std::cout << "d1: " << d1.myFunc(2).transpose() << "\n";
Derived2 d2;
std::cout << "d2: " << d2.myFunc(2).transpose() << "\n";
return 0;
}
On my machine, this prints
d1: 4 5
d2: 4 6
Ok, I think I found a reasonably readable solution. Feedback is still welcome.
I just defined another template parameter, a bool, which tells whether the derived class holds data, and defined the return type using std::conditional and that bool:
#include <Eigen/Dense>
#include <type_traits>
#include <utility>
#include <iostream>
using Matrix2Xd = Eigen::Matrix<double,2,Eigen::Dynamic>;
using Eigen::Vector2d;
template<typename T, bool hasData>
class Base
{
public:
auto myFunc(int) const ->
std::conditional_t<hasData, Matrix2Xd::ConstColXpr, Vector2d>;
protected:
Base();
};
template<typename T, bool hasData>
Base<T, hasData>::Base() {
static_assert( std::is_member_function_pointer_v<decltype(&T::myFuncImp)> );
}
template<typename T, bool hasData>
auto Base<T, hasData>::myFunc(int i) const ->
std::conditional_t<hasData, Matrix2Xd::ConstColXpr, Vector2d> {
return static_cast<const T&>(*this).myFuncImp(i);
}
class Derived1 : public Base<Derived1, true>
{
private:
Matrix2Xd m_data;
public:
Derived1( Matrix2Xd&& );
private:
auto myFuncImp(int) const -> Matrix2Xd::ConstColXpr;
friend Base;
};
Derived1::Derived1( Matrix2Xd&& data ) :
m_data {data}
{}
auto Derived1::myFuncImp(int i) const -> Matrix2Xd::ConstColXpr {
return m_data.col(i);
}
class Derived2 : public Base<Derived2, false>
{
private:
auto myFuncImp(int) const -> Eigen::Vector2d;
friend Base;
};
auto Derived2::myFuncImp(int i) const -> Eigen::Vector2d {
return Eigen::Vector2d { 2*i, 3*i };
}
int main(){
Matrix2Xd m (2, 3);
m <<
0, 2, 4,
1, 3, 5;
Derived1 d1 { std::move(m) };
std::cout << "d1: " << d1.myFunc(2).transpose() << "\n";
Derived2 d2;
std::cout << "d2: " << d2.myFunc(2).transpose() << "\n";
return 0;
}
Compiles and executes fine. Bit more verbose, but at least shows the intent clearly.
Other answers are still welcome.
Note: Adding another answer, because both answers are valid, and independent.
A different way is to define a traits class. The advantage over the previous answer is, that any code that wants to use an object of type Base doesn't have to have a multitude of template parameters. Multiple template parameters kind of implies that they can be mixed and matched, but the situation here is more about one template type logically implicating which types are supposed to be used.
First, an empty traits class is defined:
template<typename T>
class BaseTraits {};
This is the full definition, not a forward declaration. Then, it has to be specialised for each type derived from Base:
class Derived1; // forward declaration for the traits class
template<>
class BaseTraits<Derived1>
{
public:
using VectorType = Matrix2Xd::ConstColXpr;
};
and
class Derived2;
template<>
class BaseTraits<Derived2>
{
public:
using VectorType = Eigen::Vector2d;
};
Now, Base can use the VectorType with a typealias:
template<typename T>
class Base
{
public:
using VectorType = typename BaseTraits<T>::VectorType;
auto myFunc(int) const -> VectorType; /* note the speaking return type */
protected:
Base();
};
with the effect that it's now clear what myFunc is supposed to return - at least as clear as the naming of the traits ;)
Here's the full code:
#include <Eigen/Dense>
#include <type_traits>
#include <utility>
#include <iostream>
template<typename T>
class BaseTraits {};
template<typename T>
class Base
{
public:
using VectorType = typename BaseTraits<T>::VectorType;
auto myFunc(int) const -> VectorType;
protected:
Base();
};
template<typename T>
Base<T>::Base() {
/* make sure the function is actually implemented, otherwise generate a
* useful error message */
static_assert( std::is_member_function_pointer_v<decltype(&T::myFuncImp)> );
}
template<typename T>
auto Base<T>::myFunc(int i) const -> VectorType {
return static_cast<const T&>(*this).myFuncImp(i);
}
using Matrix2Xd = Eigen::Matrix<double,2,Eigen::Dynamic>;
class Derived1;
template<>
class BaseTraits<Derived1>
{
public:
using VectorType = Matrix2Xd::ConstColXpr;
};
class Derived1 : public Base<Derived1>
{
private:
Matrix2Xd m_data;
public:
Derived1( Matrix2Xd&& );
private:
auto myFuncImp(int) const -> Matrix2Xd::ConstColXpr;
friend Base;
};
Derived1::Derived1( Matrix2Xd&& data ) :
m_data {data}
{}
auto Derived1::myFuncImp(int i) const -> Matrix2Xd::ConstColXpr {
return m_data.col(i);
}
class Derived2;
template<>
class BaseTraits<Derived2>
{
public:
using VectorType = Eigen::Vector2d;
};
class Derived2 : public Base<Derived2>
{
private:
auto myFuncImp(int) const -> Eigen::Vector2d;
friend Base;
};
auto Derived2::myFuncImp(int i) const -> Eigen::Vector2d {
return Eigen::Vector2d { 2*i, 3*i };
}
int main(){
Matrix2Xd m (2, 3);
m <<
0, 2, 4,
1, 3, 5;
Derived1 d1 { std::move(m) };
std::cout << "d1: " << d1.myFunc(2).transpose() << "\n";
Derived2 d2;
std::cout << "d2: " << d2.myFunc(2).transpose() << "\n";
return 0;
}
I'm trying to store and manipulate a list of template class objects with different parameter types; the template class has two parametrised methods, one returning the parameter type and a void one accepting it as input.
More specifically, I have a template class defined as follows:
template<typename T>
class Test
{
public:
virtual T a() = 0;
virtual void b(T t) = 0;
};
And different specifications of it, such as:
class TestInt : public Test<int>
{
public:
int a() {
return 1;
}
void b(int t) {
std::cout << t << std::endl;
}
};
class TestString : public Test<std::string>
{
public:
std::string a() {
return "test";
}
void b(std::string t) {
std::cout << t << std::endl;
}
};
I'd like to be able to store in one single list different objects of both TestInt and TestString type and loop through it calling one method as input for the other, as in:
for (auto it = list.begin(); it != list.end(); ++it)
(*it)->b((*it)->a());
I've looked into boost::any but I'm unable to cast the iterator to the specific class, because I don't know the specific parameter type of each stored object. Maybe this cannot be done in a statically typed language as C++, but I was wondering whether there could be a way around it.
Just for the sake of completeness, I'll add that my overall aim is to develop a "parametrised observer", namely being able to define an observer (as with the Observer Pattern) with different parameters: the Test class is the observer class, while the list of different types of observers that I'm trying to properly define is stored within the subject class, which notifies them all through the two methods a() and b().
The virtuals have actually no meaning here, since for each T the signatures are distinct.
So it seems you have Yet Another version of the eternal "how can we emulate virtual functions templates" or "how to create an interface without virtual functions":
Generating an interface without virtual functions?
How to achieve "virtual template function" in C++
The first one basically contains an idea that you could employ here.
Here's an idea of what I'd do:
Live On Coliru
#include <algorithm>
#include <iostream>
namespace mytypes {
template <typename T>
struct Test {
T a() const;
void b(T t) { std::cout << t << std::endl; }
};
template <> int Test<int>::a() const { return 1; }
template <> std::string Test<std::string>::a() const { return "test"; }
using TestInt = Test<int>;
using TestString = Test<std::string>;
}
#include <boost/variant.hpp>
namespace mytypes {
using Value = boost::variant<int, std::string>;
namespace detail {
struct a_f : boost::static_visitor<Value> {
template <typename T>
Value operator()(Test<T> const& o) const { return o.a(); }
};
struct b_f : boost::static_visitor<> {
template <typename T>
void operator()(Test<T>& o, T const& v) const { o.b(v); }
template <typename T, typename V>
void operator()(Test<T>&, V const&) const {
throw std::runtime_error(std::string("type mismatch: ") + __PRETTY_FUNCTION__);
}
};
}
template <typename O>
Value a(O const& obj) {
return boost::apply_visitor(detail::a_f{}, obj);
}
template <typename O, typename V>
void b(O& obj, V const& v) {
boost::apply_visitor(detail::b_f{}, obj, v);
}
}
#include <vector>
int main()
{
using namespace mytypes;
using AnyTest = boost::variant<TestInt, TestString>;
std::vector<AnyTest> list{TestInt(), TestString(), TestInt(), TestString()};
for (auto it = list.begin(); it != list.end(); ++it)
b(*it, a(*it));
}
This prints
1
test
1
test
Bonus Points
If you insist, you can wrap the AnyTest variant into a proper class and have a() and b(...) member functions on that:
Live On Coliru
int main()
{
using namespace mytypes;
std::vector<AnyTest> list{AnyTest(TestInt()), AnyTest(TestString()), AnyTest(TestInt()), AnyTest(TestString())};
for (auto it = list.begin(); it != list.end(); ++it)
it->b(it->a());
}
Expanding on my comment above, the simplest what I can currently think of to achieve what you are trying to do - at least as I understood it from your example code - is the following:
/* Interface for your container, better not forget the destructor! */
struct Test {
virtual void operate(void) = 0;
virtual ~Test() {}
};
/* Implementation hiding actual type */
template<typename T>
struct TestImpl : public T, public Test {
void operate(void) {
T::b(T::a());
}
};
/* Actual code as template policies */
struct IntTest {
int a(void) {
return 42;
}
void b(int value) {
std::cout << value << std::endl;
}
};
struct StringTest {
std::string a(void) {
return "Life? Don't talk to me about life.";
}
void b(std::string value) {
std::cout << value << std::endl;
}
};
You would then need to create a container for objects of class Test and fill it with objects of the respective TestImpl<IntTest>, TestImpl<StringTest>, and so on. To avoid object slicing you need reference or pointer semantics, that is std::vector<std::unique_ptr<Test> > for example.
for (auto it = list.begin(); it != list.end(); ++it) {
(*it)->operate();
}
I have written a small piece of code where I am able to call setter and getter functions packed within a functoid using mem_fun templates.
I now would like to use this approach on top of a class hierarchy where every class might have getter and setter which can be registered as pair within a vector or array to be able to call the getter and setter if needed. GUIObject and GUICompositeObject are example classes out of the described class hierarchy.
The bound_mem_fun_t for the objects have unfortunately different types and thats the reason I don't know how to integrate them into an array/vector of pointers to the functors.
In c++11 I would use std::function. Is there a way to emulate this in c++98?
Because our compiler support only c++98 I cannot use the new features of c++11 or c++14. Also boost is not allowed.
#include <functional>
class GUIObject
{
int m_Alpha;
public:
void SetAlpha(int a) { m_Alpha = a;};
int GetAlpha() {return m_Alpha;};
};
class GUICompositeObject: public GUIObject
{
int m_NumOfChilds;
public:
void SetNumOfChilds(int NumOfChilds) { m_NumOfChilds = NumOfChilds;};
int GetNumOfChilds() {return m_NumOfChilds;};
};
template<typename T>
struct bound_mem_fun_t
{
bound_mem_fun_t(std::mem_fun_t<int, T> GetFunc, std::mem_fun1_t<void, T, int> SetFunc, T* o) :
m_GetFunc(GetFunc), m_SetFunc(SetFunc), obj(o) { } ;
int operator()() { return m_GetFunc(obj); } ;
void operator()(int i) { m_SetFunc(obj, i); } ;
std::mem_fun_t<int, T> m_GetFunc;
std::mem_fun1_t<void, T, int> m_SetFunc;
T* obj;
};
int main()
{
GUIObject kGUIObject;
GUICompositeObject kCompObj;
bound_mem_fun_t<GUIObject> GUIObjectFunc(std::mem_fun(&GUIObject::GetAlpha), std::mem_fun(&GUIObject::SetAlpha), &kGUIObject);
GUIObjectFunc(17);
int ii = GUIObjectFunc();
bound_mem_fun_t<GUICompositeObject> GUICompObjectFunc(std::mem_fun(&GUICompositeObject::GetNumOfChilds), std::mem_fun(&GUICompositeObject::SetNumOfChilds), &kCompObj);
GUICompObjectFunc(17);
int iChilds = GUICompObjectFunc();
return 0;
}
Here is the complete solution after #filmors answer:
#include <functional>
#include <vector>
#include <iostream>
class GUIObject
{
int m_Alpha;
public:
void SetAlpha(int a) { m_Alpha = a;};
int GetAlpha() {return m_Alpha;};
};
class GUICompositeObject: public GUIObject
{
int m_NumOfChilds;
public:
void SetNumOfChilds(int NumOfChilds) { m_NumOfChilds = NumOfChilds;};
int GetNumOfChilds() {return m_NumOfChilds;};
};
struct bound_mem_fun_base
{
virtual int operator()() =0;
virtual void operator()(int) =0;
};
template<typename T>
struct bound_mem_fun_t : public bound_mem_fun_base
{
bound_mem_fun_t(std::mem_fun_t<int, T> GetFunc, std::mem_fun1_t<void, T, int> SetFunc, T* o) :
m_GetFunc(GetFunc), m_SetFunc(SetFunc), obj(o) { } ;
virtual int operator()() { return m_GetFunc(obj); } ;
virtual void operator()(int i) { m_SetFunc(obj, i); } ;
std::mem_fun_t<int, T> m_GetFunc;
std::mem_fun1_t<void, T, int> m_SetFunc;
T* obj;
};
template<typename T> bound_mem_fun_t<T>* make_setter(std::mem_fun_t<int, T> GetFunc, std::mem_fun1_t<void, T, int> SetFunc, T* o)
{
return new bound_mem_fun_t<T> (GetFunc, SetFunc, o);
}
int main()
{
GUIObject kGUIObject;
GUICompositeObject kCompObj;
std::vector<bound_mem_fun_base*> kBoundVector;
kBoundVector.push_back(new bound_mem_fun_t<GUIObject> (std::mem_fun(&GUIObject::GetAlpha), std::mem_fun(&GUIObject::SetAlpha), &kGUIObject));
kBoundVector.push_back(new bound_mem_fun_t<GUICompositeObject> (std::mem_fun(&GUICompositeObject::GetNumOfChilds), std::mem_fun(&GUICompositeObject::SetNumOfChilds), &kCompObj));
kBoundVector.push_back(make_setter<GUIObject> (std::mem_fun(&GUIObject::GetAlpha), std::mem_fun(&GUIObject::SetAlpha), &kGUIObject));
kBoundVector.push_back(make_setter<GUICompositeObject> (std::mem_fun(&GUICompositeObject::GetNumOfChilds), std::mem_fun(&GUICompositeObject::SetNumOfChilds), &kCompObj));
for (int i = 0; i < 4 ; i++)
{
(*kBoundVector[i])(i*10);
int res = (*kBoundVector[i])();
std::cout << "Getter result " << res << "\n";
}
return 0;
}
Unfortunately the make_setter function does not really shorten the creation of the functor. Any ideas will be welcome.
Just give your bound_mem_fun_t<T> a common base class and use dynamic dispatch to solve your problem:
struct bound_mem_fun_base {
virtual int operator()() = 0;
virtual void operator()(int) = 0;
};
template <typename T>
struct bound_mem_fun_t : bound_mem_fun_t ...
Then you can keep pointers to bound_mem_fun_base in your vector and call the elements as (*v[0])().
Also, TR1 does contain std::tr1::function, is that available?
First a remark on std::function from c++11: That will not solve your problem, because you need an already bounded function pointer. This pointer must be bound to your object. I believe what you need is an own implementation to std::bind.
I started only a very! small Binder class which is hopefully a starting point for your needs. If you need to have template parameter lists in older c++ versions, take a look for loki. http://loki-lib.sourceforge.net/
As a hint I can give you a short example of what i did:
class A
{
private:
int val;
public:
A(int i): val(i) {}
void Do(int i) { std::cout << "A " << val<< " " << i << std::endl; }
};
class B
{
private:
int val;
public:
B(int i): val(i){}
void Go(int i) { std::cout << "B " << val << " " << i << std::endl; }
};
class Base
{
public:
virtual void operator()(int i)=0;
};
template <typename T>
class Binder: public Base
{
void (T::*fnct)(int);
T* obj;
public:
Binder( void(T::*_fnct)(int), T*_obj):fnct(_fnct),obj(_obj){}
void operator()(int i)
{
(obj->*fnct)(i);
}
};
int main()
{
A a(100);
B b(200);
// c++11 usage for this example
//std::function<void(int)> af= std::bind( &A::Do, &a, std::placeholders::_1);
//af(1);
// hand crafted solution
Base* actions[2];
actions[0]= new Binder<A>( &A::Do, &a);
actions[1]= new Binder<B>( &B::Go, &b);
actions[0]->operator()(55);
actions[1]->operator()(77);
}