I want to define a base template class in a way so that it takes variadic template arguments and defines a virtual method for each argument, where the parameter is the argument type.
E.g. Base<int, bool, string> should give me 3 virtual methods: Foo(int), Foo(bool), and Foo(string).
I tried the following:
template <typename Param>
struct BaseSingle
{
virtual void Foo(Param) {};
};
template <typename... Params>
struct Base : public BaseSingle<Params>...
{
};
Unfortunately, Foo becomes ambiguous. I can't get the using BaseSingle<Params>::Foo... syntax to work. Is there a way?
I know that, alternatively, I can recursively inherit from BaseSingle and pass in the remaining params. Are there perf implications of that?
Here is a suggestion that requires exact type matching:
#include <utility>
#include <typeinfo>
#include <string>
#include <iostream>
#include <cstdlib>
#include <memory>
#include <cxxabi.h>
using namespace std;
// GCC demangling -- not required for functionality
string demangle(const char* mangled) {
int status;
unique_ptr<char[], void (*)(void*)> result(
abi::__cxa_demangle(mangled, 0, 0, &status), free);
return result.get() ? string(result.get()) : "ERROR";
}
template<typename Param>
struct BaseSingle {
virtual void BaseFoo(Param) {
cout << "Hello from BaseSingle<"
<< demangle(typeid(Param).name())
<< ">::BaseFoo" << endl;
};
};
template<typename... Params>
struct Base : public BaseSingle<Params>... {
template<typename T> void Foo(T&& x) {
this->BaseSingle<T>::BaseFoo(forward<T>(x));
}
};
int main() {
Base<string, int, bool> b;
b.Foo(1);
b.Foo(true);
b.Foo(string("ab"));
}
But IMO your own suggestion using recursive inheritance sounds more elegant.
Related
I use std::experimental::is_detected to determine if class has certain member functions:
#include <utility>
#include <experimental/type_traits>
template<typename USC>
class Descriptor
{
private:
template<class T>
using has_member1_t =
decltype(std::declval<T>().member1(std::declval<std::vector<char> &>()));
public:
static constexpr bool has_member1 =
std::experimental::is_detected_convertible_v<long long,
has_member1_t,
USC>;
};
The problem is I also need to determine if class has certain template member function with following signature:
template<typename Derived>
int member2(Eigen::ArrayBase<Derived> &&)
I've tried to do it like so:
//Inside Descriptor
template<class T, class U>
using has_member2_t =
decltype(std::declval<T>().member2(std::declval<Eigen::ArrayBase<U> &&>()));
static constexpr bool has_member2 =
std::experimental::is_detected_convertible_v<long long,
has_member2_t,
USC>;
but it doesn't work. As I'm not really experienced with C++ TMP I would like to know is there a way to achieve this with std::experimental::is_detected or some other utility?
If c++20 is an option, this kind of code has been made a lot easier to both read and write by using concepts.
#include <iostream>
#include <vector>
struct Foo {
int member1(int) {
return 1;
}
template <typename T>
double member2(std::vector<T>) {
return 2.5;
}
};
struct Bar {};
template <typename T>
concept MyConcept = requires (T t) {
{ t.member1(0) } -> std::same_as<int>; // We can check return type
{ t.template member2<int>(std::vector<int>{}) }; // but we don't have to
};
int main() {
static_assert(MyConcept<Foo>);
static_assert(!MyConcept<Bar>);
}
The issue with your attempt is that you are not passing anything as U for the check. I would also modify it to use the .template member2<...> syntax to explicitly check for a template.
Here is an example of that.
#include <iostream>
#include <vector>
#include <utility>
#include <experimental/type_traits>
struct Foo {
int member1(int) {
return 1;
}
template <typename T>
double member2(std::vector<T>) {
return 2.5;
}
};
struct Bar {};
template<class T, class U>
using has_member2_t =
decltype(std::declval<T>().template member2<U>(std::declval<std::vector<U> &&>()));
int main() {
static constexpr bool has_member2_Foo =
std::experimental::is_detected_convertible_v<long long,
has_member2_t,
Foo, double>;
static constexpr bool has_member2_Bar =
std::experimental::is_detected_convertible_v<long long,
has_member2_t,
Bar, double>;
static_assert(has_member2_Foo);
static_assert(!has_member2_Bar);
}
I am wondering whether there is a practical way of writing something like the following code using the C++17 standard:
#include <string>
#include <functional>
#include <unordered_map>
template <class Arg>
struct Foo
{
using arg_type = Arg;
using fun_type = std::function< void(Arg&) >;
fun_type fun;
void call( Arg& arg ) { fun(arg); }
};
struct Bar
{
using map_type = std::unordered_map<std::string,Foo>; // that's incorrect
map_type map;
auto& operator[] ( std::string name ) { return map[name]; }
};
In the code above, the template argument of class Foo corresponds to the input type of some unary function which returns nothing. Different instances of Foo with different template types correspond to functions taking arguments of different types. The class Bar simply aims at assigning a name to these functions, but obviously the current declaration of the map is incorrect because it needs to know about the template type of Foo.
Or does it?
Doing this with a compile-time check is, unfortunately, not feasible. You can, however, provide that functionality with a runtime check.
A map's value type can only be one single type, and Foo<T> is a different type for each T. However, we can work around this by giving every Foo<T> a common base class, have a map of pointers to it, and use a virtual function to dispatch call() to the appropriate subclass.
For this though, the type of the argument must also always be the same. As mentioned by #MSalters, std::any can help with that.
Finally, we can wrap all that using the pimpl pattern so that it looks like there's just a single neat Foo type:
#include <cassert>
#include <string>
#include <functional>
#include <any>
#include <unordered_map>
#include <memory>
struct Foo {
public:
template<typename T, typename FunT>
void set(FunT fun) {
pimpl_ = std::make_unique<FooImpl<T, FunT>>(std::move(fun));
}
// Using operator()() instead of call() makes this a functor, which
// is a little more flexible.
void operator()(const std::any& arg) {
assert(pimpl_);
pimpl_->call(arg);
}
private:
struct IFooImpl {
virtual ~IFooImpl() = default;
virtual void call( const std::any& arg ) const = 0;
};
template <class Arg, typename FunT>
struct FooImpl : IFooImpl
{
FooImpl(FunT fun) : fun_(std::move(fun)) {}
void call( const std::any& arg ) const override {
fun_(std::any_cast<Arg>(arg));
}
private:
FunT fun_;
};
std::unique_ptr<IFooImpl> pimpl_;
};
// Usage sample
#include <iostream>
void bar(int v) {
std::cout << "bar called with: " << v << "\n";
}
int main() {
std::unordered_map<std::string, Foo> table;
table["aaa"].set<int>(bar);
// Even works with templates/generic lambdas!
table["bbb"].set<float>([](auto x) {
std::cout << "bbb called with " << x << "\n";
});
table["aaa"](14);
table["bbb"](12.0f);
}
see on godbolt
I am trying to create a concept for use with boost::any. This concept should say that
a class has ha member function with signatur void templateFunction(T t). I have gotten this to compile and working fine, but only for one type at a time. Is what I am trying to do impossible?
#include <iostream>
#include <boost/type_erasure/any.hpp>
#include <boost/type_erasure/any_cast.hpp>
#include <boost/type_erasure/builtin.hpp>
#include <boost/type_erasure/operators.hpp>
#include <boost/type_erasure/member.hpp>
#include <boost/type_erasure/free.hpp>
#include <boost/mpl/vector.hpp>
#include <boost/any.hpp>
using namespace std;
namespace mpl = boost::mpl;
using namespace boost::type_erasure;
class Foo
{
public:
template <class T>
void templateFunction(T t)
{
cout << t << endl;
}
};
template<class C, class T>
struct has_template_function
{
static void apply(C& cont, const T& arg) { cont.templateFunction(arg); }
};
namespace boost
{
namespace type_erasure
{
template<class C, class T, class Base>
struct concept_interface<has_template_function<C, T>, Base, C> : Base
{
void templateFunction(typename as_param<Base, const T&>::type arg)
{ call(has_template_function<C, T>(), *this, arg); }
};
}
}
int main()
{
any<has_template_function<_self, int>, _self&> c = Foo();
c.templateFunction(5);
//Compile error: cannot convert parameter 1 from 'const char [6]' to 'const int &'
//c.templateFunction("Hello");
return 0;
}
This is kind of possible by overloading, and documented in the official Boost.TypeErasure documentation.
The caveat is, as said in the comments:
You can't type-erase templates and keep their polymorphic nature
Therefore, you will have to specify the overloads explicitly in the requirements for your boost::typeerasure::any type.
You need to modify your concept interface as described in the docs, and add a string overload to the requirements section.
Your example, modified to handle overloads:
#include <iostream>
#include <boost/type_erasure/any.hpp>
#include <boost/type_erasure/any_cast.hpp>
#include <boost/type_erasure/builtin.hpp>
#include <boost/type_erasure/operators.hpp>
#include <boost/type_erasure/member.hpp>
#include <boost/type_erasure/free.hpp>
#include <boost/mpl/vector.hpp>
#include <boost/any.hpp>
#include <string>
#include <utility>
using namespace std;
namespace mpl = boost::mpl;
using namespace boost::type_erasure;
struct FooStruct
{
template <class T>
void templateFunction(T t)
{
cout << t << endl;
}
};
template<class T, class U>
struct has_template_function
{
static void apply(T& t, const U& u) { t.templateFunction(u); }
};
namespace boost {
namespace type_erasure {
template<class T, class U, class Base, class Enable>
struct concept_interface< ::has_template_function<T, U>, Base, T, Enable> : Base
{
typedef void _fun_defined;
void templateFunction(typename as_param<Base, const U&>::type arg)
{
call(::has_template_function<T, U>(), *this, arg);
}
};
template<class T, class U, class Base>
struct concept_interface< ::has_template_function<T, U>, Base, T, typename Base::_fun_defined> : Base
{
using Base::templateFunction;
void templateFunction(typename as_param<Base, const U&>::type arg)
{
call(::has_template_function<T, U>(), *this, arg);
}
};
}
}
ostream& operator<<(ostream& os, const std::pair<int, string>& pair) {
os << "(" << pair.first << ", " << pair.second << ")";
return os;
}
int main()
{
any<
mpl::vector
<
has_template_function<_self, int>,
has_template_function<_self, std::string>,
has_template_function<_self, std::pair<int,std::string>>
>
, _self&> c = FooStruct();
c.templateFunction(5);
c.templateFunction("Hello");
c.templateFunction(std::make_pair(5, "Hello"));
return 0;
}
As a personal exercise, I want to implement the visitor pattern using shared_ptr. I am familiar with Robert Martin's acyclic visitor paper but find the intrusive nature of the virtual accept() and necessary creation of an {X}Visitor class for each {X} class unpleasant. I like the boost::static_visitor class as it encapsulates all the logic locally without the necessity of {X}::accept() and {X}Visitor.
What I am looking for is a hint (as I said, I'm doing this as an exercise) of how to create the template function function rip I mention below. I think it should be of the form:
template <typename U, typename T1, typename T2, ...>
boost::variant<T1, T2, ...> rip(U& p, boost::static_visitor<T1, T2, ...> sv)
{
if (T1 t1 = dynamic_cast<T1>(p)) return boost::variant<T1, ...>(t1);
... and so on, splitting static_visitor
return 0; // or throw an exception
}
Any hints or pointers to tutorials doing similar things would be appreciated. Thanks.
#include <algorithm>
#include <cstdlib>
#include <iostream>
#include <memory>
#include <boost/bind.hpp>
#include <boost/variant.hpp>
struct Base {};
struct A : Base {};
struct B : Base {};
struct C : Base {};
typedef std::shared_ptr<Base> base_ptr;
typedef boost::variant<A*,B*,C*> base_variant;
struct variant_visitor : public boost::static_visitor<void> {
void operator()(A*, base_ptr) const {std::cout << "A*\n";}
void operator()(B*, base_ptr) const {std::cout << "B*\n";}
void operator()(C*, base_ptr) const {std::cout << "C*\n";}
};
int main(int, char**)
{
// This works, of course.
base_ptr b(new A());
base_variant v(new A());
boost::apply_visitor(boost::bind(variant_visitor(), _1, b), v);
// How could we use a shared_ptr with a variant? I almost see
// the template magic, a function to iterate over the template
// types from the variant_visitor and return an "any<...>".
// base_variant rip(base_ptr&, variant_visitor) {...}
// boost::apply_visitor(boost::bind(variant_visitor(), _1, b), rip(b, variant_visitor()));
return EXIT_SUCCESS;
}
I may be misunderstanding the question, but if you want to use the same variant_visitor for a variant containing shared pointers instead of plain pointers, perhaps this can be achieved with another visitor that obtains the pointer from the shared_ptr and passes it on to the other visitor.
#include <algorithm>
#include <cstdlib>
#include <iostream>
#include <boost/shared_ptr.hpp>
#include <boost/bind.hpp>
#include <boost/variant.hpp>
struct Base {};
struct A : Base {};
struct B : Base {};
struct C : Base {};
typedef boost::shared_ptr<Base> base_ptr;
typedef boost::variant<boost::shared_ptr<A>,boost::shared_ptr<B>,boost::shared_ptr<C> > base_variant;
template <class Visitor>
struct visit_shared_ptr_get: public boost::static_visitor<typename Visitor::result_type>
{
//for unary visitors
template <class FirstArg>
typename Visitor::result_type operator()(FirstArg& first) const
{
return Visitor()(first.get());
}
//for binary visitors, only the first argument is "ripped"
template <class FirstArg, class SecondArg>
typename Visitor::result_type operator()(FirstArg& first, SecondArg& second) const
{
return Visitor()(first.get(), second);
}
};
struct variant_visitor : public boost::static_visitor<void> {
void operator()(A*, base_ptr) const {std::cout << "A*\n";}
void operator()(B*, base_ptr) const {std::cout << "B*\n";}
void operator()(C*, base_ptr) const {std::cout << "C*\n";}
};
int main(int, char**)
{
// This works, of course.
base_ptr b(new A());
base_variant v(boost::shared_ptr<A>(new A()));
boost::apply_visitor(boost::bind(visit_shared_ptr_get<variant_visitor>(), _1, b), v);
return EXIT_SUCCESS;
}
Edit: a downcaster that you seem to be envisioning.
#include <stdexcept>
#include <boost/type_traits.hpp>
#include <boost/utility/enable_if.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/variant.hpp>
#include <boost/variant/variant_fwd.hpp>
#include <boost/preprocessor/repetition.hpp>
//dynamic_cast will only compile if the target type is a pointer
template <class Derived, class Base, class Variant>
typename boost::enable_if<boost::is_pointer<Derived>, bool>::type cast_if_pointer( Base* b, Variant& variant)
{
if (Derived p = dynamic_cast<Derived>(b)) { variant = p; return true; }
return false;
}
//weeds out boost's unused template parameters and other non-pointers
template <class Derived, class Base, class Variant>
typename boost::disable_if<boost::is_pointer<Derived>, bool>::type cast_if_pointer( Base*, Variant& )
{
return false;
}
template <class P, BOOST_VARIANT_ENUM_PARAMS(class T)>
void rip(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>& variant, const boost::shared_ptr<P>& smart_ptr)
{
#define ATTEMPT_CAST(z, n, type) if (cast_if_pointer<T ## n >(smart_ptr.get(), variant)) return;
BOOST_PP_REPEAT(BOOST_VARIANT_LIMIT_TYPES, ATTEMPT_CAST, T)
#undef ATTEMPT_CAST
throw std::bad_cast();
}
struct Base
{
virtual ~Base() {}
};
struct A : Base {};
struct B : Base {};
struct C : Base {};
typedef boost::shared_ptr<Base> base_ptr;
typedef boost::variant<A*,B*,C*> base_variant;
int main(int, char**)
{
base_ptr b(new A());
base_variant v;
rip(v, b);
return EXIT_SUCCESS;
}
You can't use the visitor for type deduction, because it has only one template argument - for the result_type. Its operator() either can or cannot be invoked on all the types any arbitrary boost::variant might be storing.
I'm only guessing the following might be what you are looking for (my first use of boost's preprocessor library):
#include <algorithm>
#include <cstdlib>
#include <iostream>
#include <memory>
#include <boost/bind.hpp>
#include <boost/variant.hpp>
#include <boost/variant/variant_fwd.hpp>
#include <boost/preprocessor/repetition.hpp>
#define SHARED_PTR_TO_PTR(z, n, text) BOOST_PP_COMMA_IF(n) typename shared_ptr_to_ptr<text ## n>::type
template <class T>
struct shared_ptr_to_ptr { typedef T type; };
template <class T>
struct shared_ptr_to_ptr<std::shared_ptr<T> > {typedef T* type; };
template <class T>
struct unsmartify_variant;
template <BOOST_VARIANT_ENUM_PARAMS(typename T)>
struct unsmartify_variant<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T) > >
{
typedef boost::variant<BOOST_PP_REPEAT(BOOST_VARIANT_LIMIT_TYPES, SHARED_PTR_TO_PTR, T)> type;
};
template <class Variant>
struct get_visitor: boost::static_visitor<typename unsmartify_variant<Variant>::type >
{
template <class SharedPtr>
typename unsmartify_variant<Variant>::type operator()(SharedPtr& p) const
{
return p.get();
}
};
template <class Variant>
typename unsmartify_variant<Variant>::type rip(Variant& variant)
{
return boost::apply_visitor(get_visitor<Variant>(), variant);
}
struct Base {};
struct A : Base {};
struct B : Base {};
struct C : Base {};
typedef std::shared_ptr<Base> base_ptr;
typedef boost::variant<std::shared_ptr<A>,std::shared_ptr<B>,std::shared_ptr<C> > base_variant;
struct variant_visitor : public boost::static_visitor<void> {
void operator()(A*, base_ptr) const {std::cout << "A*\n";}
void operator()(B*, base_ptr) const {std::cout << "B*\n";}
void operator()(C*, base_ptr) const {std::cout << "C*\n";}
};
int main(int, char**)
{
// This works, of course.
base_ptr b(new A());
base_variant v(std::shared_ptr<A>(new A()));
unsmartify_variant<base_variant>::type k = rip(v);
boost::apply_visitor(boost::bind(variant_visitor(), _1, b), k);
return EXIT_SUCCESS;
}
The greatest problem is that boost::variant takes a fixed number of arguments.
Also it appears that the variant is passed to apply_visitor by non-const reference, meaning the result of rip must be stored in a named variable.
I am trying to specialize some utility code on const member functions, but have problems to get a simple test-case to work.
To simplify the work i am utilizing Boost.FunctionTypes and its components<FunctionType> template - a MPL sequence which should contain the tag const_qualified for const member functions.
But using the test-code below, the specialization on const member functions fails. Does anybody know how to make it work?
The test-code prints out (using VC8 and boost 1.40):
non-const
non-const
Expected output is:
non-const
const
The test-code itself:
#include <iostream>
#include <boost/function.hpp>
#include <boost/bind.hpp>
#include <boost/function_types/function_type.hpp>
#include <boost/mpl/contains.hpp>
namespace ft = boost::function_types;
namespace mpl = boost::mpl;
template<typename F>
struct select
{
template<bool IsConst /* =false */>
struct helper {
static void f() { std::cout << "non-const" << std::endl; }
};
template<>
struct helper</* IsConst= */ true> {
static void f() { std::cout << "const" << std::endl; }
};
typedef ft::components<F> components;
typedef typename mpl::contains<components, ft::const_qualified>::type const_qualified;
typedef helper<const_qualified::value> result;
};
typedef boost::function<void (void)> Functor;
template<typename MF>
Functor f(MF f)
{
return boost::bind(&select<MF>::result::f);
}
class C
{
public:
void f1() {}
void f2() const {}
};
int main()
{
f(&C::f1)(); // prints "non-const" as expected
f(&C::f2)(); // prints "non-const", expected "const"
}
While its still unclear to me why the approach via function_types::components<> doesn't work, i realized that there is a simpler approach with Boost.FunctionTypes to specialize on const member functions:
The classification meta functions like is_member_function_pointer<> optionally take a tag parameter ...
template<typename F>
struct select
{
/* ... helper-struct as before */
typedef ft::is_member_function_pointer<F, ft::const_qualified> const_qualified;
typedef helper<const_qualified::value> result;
};
I have not tested it, but shouldn't
typedef mpl::contains<components, ft::const_qualified> const_qualified;
be
typedef typename mpl::contains<components::type, ft::const_qualified>::type const_qualified;