Fold expresion & CRTP - c++

I'm writing this small application trying to test about fold expressions and i can't get it to compile, it complaints about ambiguous request on method Play, i don't understand why the signature of the function Play should be different on both calls..
#include <iostream>
#include <any>
using namespace std;
struct A
{
void play() const
{
std::cout << "A..." << std::endl;
}
};
struct B
{
void play() const
{
std::cout << "B..." << std::endl;
}
};
template<typename TKey>
struct BaseValue
{
void Play(const TKey& arg)
{
arg.play();
}
};
template<typename... Keys>
struct MyMap : public BaseValue<Keys>...
{
};
int main()
{
MyMap<A, B> oMyMap;
A a;
oMyMap.Play(a)
return 0;
}

Beside the constness mentioned in the comment, the fix is
template<typename... Keys>
struct MyMap : public BaseValue<Keys>...
{
using BaseValue<Keys>::Play ...;
};
The initial problem, has to do with name-lookup, which happens before overload resolution, see [this answer] https://stackoverflow.com/a/60775944/2412846) and the linked duplicates.

Related

How to pass a C++ Template instance to a function?

How can I pass any object of an templated class to another function in C++11?
In the snippet below passInObj does not compile because it complains about Printer&. I want to pass in any Printer it does not matter which template T I have used.
How can I do this and why does the solution below not work?
#include <iostream>
#include <vector>
template <typename T>
class Printer {
public:
Printer(const T& tl) : t(tl) {}
void print() const {
for (auto x : t) {
std::cout << x << std::endl;
}
}
const T &t;
};
// THIS LINE DOES NOT COMPILE
void passInObj(const Printer& p) {
p.print();
}
int main() {
std::vector<std::string> vec;
vec.push_back("ABC");
Printer<std::vector<std::string>> printer(vec);
printer.print();
passInObj(p);
return 0;
}
How can I do this
You need to make it into a function template:
template <class T>
void passInObj(const Printer<T>& p) {
p.print();
}
Demo
and why does the solution below not work?
Because Printer is not a type, it's only a template. For passInObj to work with any Printer<T>, you need to make the function into a function template so that it'll be instantiated for every Printer<T> which is used to call it.
While #TedLyngmo's answer should be your go-to by default, you can also do this via a polymorphic interface if you cannot make passInObj() a template for some reason or other.
This is done by adding a base interface class that will be derived by all Printer<> classes:
#include <iostream>
#include <vector>
class IPrinter {
public:
virtual void print() const = 0;
// Either that or public and virtual
protected:
~IPrinter() = default;
};
template <typename T>
class Printer : public IPrinter {
public:
Printer(const T& tl) : t(tl) {}
void print() const override {
for (auto x : t) {
std::cout << x << std::endl;
}
}
const T &t;
};
void passInObj(const IPrinter& p) {
p.print();
}
int main() {
std::vector<std::string> vec;
vec.push_back("ABC");
Printer<std::vector<std::string>> printer(vec);
printer.print();
passInObj(p);
return 0;
}

Resolving overloading ambiguity with multiple inheritance of base class templates in C++

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.

Template type object constructed in class C++

How can I do something like this? I want to create a object of class C and use parameters. To elaborate, the error here is the compiler reads this as a conversion, instead of me creating an object with parameters.
EDIT: for those who still don't understand, foobar is irrelevant. I've removed it as the error still occurs without the function.
// define foobar else where
template <class C>
class Dummy {
void foo(int bar) {
C dumdum = C(bar); // Error - '<function-style-cast>': cannot convert from initializer-list to 'C'
}
}
How does that help me?
You can make foo a function template that accepts a parameter pack to make it general.
Example program:
#include <iostream>
#include <sstream>
#include <string>
template <class C>
class Dummy {
public:
template <typename... Args>
void foo(Args... args ) {
foobar(C(args...));
}
};
struct Foo
{
Foo(int, int) {}
};
struct Bar
{
Bar(int) {}
};
struct Baz
{
};
void foobar(Foo)
{
std::cout << "In foobar(Foo)\n";
}
void foobar(Bar)
{
std::cout << "In foobar(Bar)\n";
}
void foobar(Baz)
{
std::cout << "In foobar(Baz)\n";
}
int main()
{
Dummy<Foo>().foo(10, 20);
Dummy<Bar>().foo(10);
Dummy<Baz>().foo();
}
Output:
In foobar(Foo)
In foobar(Bar)
In foobar(Baz)
Have you tried something like:
C dumdum(bar);
Or:
C dumdum{bar};
?
class C {
public:
C(int a) {}
};
template <class C>
class Dummy {
public:
void foo(int bar) {
C dumdum = C(bar);
}
};
int main() {
Dummy<C> dummy;
dummy.foo(2);
return 0;
}
I didn't see any errors.

Calling parametrised method on list items with different template parameters

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();
}

template class multiple inheritance compiler unable to resolve ambiguity

I'll paste the relevant code only
Template class:
template<class TMsgType, class TKeyType>
struct mapped_subscription_handler
{
protected:
typedef std::function<void(TKeyType const &, TMsgType*)> handler_t;
typedef std::unordered_multimap<TKeyType, subscr_obj<handler_t>> map_t;
public:
void call(TKeyType const & key, TMsgType* msg)
{
//blah
}
public:
handler_id_t register_handler(TKeyType const & key, handler_t handler)
{
//blah
}
void unregister_handler(TKeyType key, handler_id_t id)
{
//blah
}
private:
map_t _map;
};
Implementation class:
typedef clients::mapped_subscription_handler<NS_Snap::NS_MD::DepSnapshot, clients::header_info<NS_Snap::NS_DEF::Header>::mdid_t> depth_handler_t;
typedef clients::mapped_subscription_handler<NS_Snap::NS_MD::TrdSnapshot, clients::header_info<NS_Snap::NS_DEF::Header>::mdid_t> trd_handler_t;
class data_client
:public depth_handler_t,
public trd_handler_t
{
public:
data_client(const std::string & host, int port);
virtual ~data_client();
clients::handler_id_t register_on_connect(std::function<void()> connect_handler);
using depth_handler_t::register_handler;
using trd_handler_t::register_handler;
using depth_handler_t::unregister_handler;
using trd_handler_t::unregister_handler;
};
Usage:
class time_comparer
{
internal_clients::data_client *_int_client;
void whenever()
{
//Compiler complains about ambiguous call here.
_int_client->register_handler(rep->GetId(), boost::bind(&time_comparer::on_internal_depth, this, _1, _2));
}
void on_internal_depth(uint64_t const & key, NS_Snap::NS_MD::DepSnapshot* depth)
{
//blah
}
};
The compiler complains of ambiguous reference when I call register_handler. Shouldn't it be able to identify which register_handler I am calling (based on boost::bind type)? Otherwise I have to qualify the call with the class name which is ugly.
EDIT:
Based on input from Sebastian Redl
This simpler example encounters the same problem
#include <iostream>
#include <functional>
template<class T>
struct test_template
{
template<class TArg>
void do_(T t, TArg arg)
{
t(arg);
}
};
class test_class :
public test_template<std::function<void(char*)>>,
public test_template<std::function<void(int)>>
{
public:
using test_template<std::function<void(char*)>>::do_;
using test_template<std::function<void(int)>>::do_;
};
int main()
{
test_class tc;
tc.do_([](int x){std::cout << x << std::endl; }, 10);
tc.do_([](char* x) {std::cout << x << std::endl; }, "what");
return 0;
}
Is there any way around this without explicitly specifying the overload when calling? i.e.
tc.test_template<std::function<void(int)>>::do_([](int x){std::cout << x << std::endl; }, 10);
In the simplified example, you may use SFINAE to remove template based mostly on the non function argument.
template<class T>
struct test_template
{
template<class TArg>
auto do_(T t, TArg arg)
-> decltype(t(arg), void())
{
t(arg);
}
};
Live demo
std::function is very liberal in conversions to it, and in particular the standard doesn't require the conversion to be SFINAEd out if the passed function object isn't compatible. So both function types appear to be constructable from the binds, which is why you get an ambiguity.