I want to implement a static cast to one of the classes from a set, passed as variadic template parameters:
struct Base {
int tag_value;
};
struct Derived1 : public Base {
static constexpr int tag = 1;
Derived1() : Base{tag} {}
int foo() { return 100; }
};
struct Derived2 : public Base {
static constexpr int tag = 2;
Derived2() : Base{tag} {}
int foo() { return 200; }
};
struct Derived3 : public Base {
static constexpr int tag = 3;
Derived3() : Base{tag} {}
int foo() { return 300; }
};
template <class ... Candidates, class Fn>
auto apply_casted(Base & base, Fn fn) {
//compare base::tag_value with each Candidate::tag
//static_cast<> base to Candidate if match
//call fn with base casted to matched Derived
return fn(/*...*/);
}
int main() {
Derived2 d2;
Base & b = d2;
// should throw error (b.tag_value doesn't match neither Derived1::tag nor Derived3::tag
auto v1 = apply_casted<Derived1, Derived3>(b, [](auto d) {
return d.foo();
});
// should static_cast b to Derived2 and return foo() (200)
auto v2 = apply_casted<Derived1, Derived2>(b, [](auto d) {
return d.foo(); //calls Derived2::foo()
});
}
Well, I hope the code speaks for itself. Code to get started: https://godbolt.org/z/WfaFt-
I'm looking for implementation of apply_casted. How to iterate Candidates... at compile time is probably the most difficult part.
template <typename Candidate, typename... Candidates, typename Fn>
auto apply_casted(Base& base, Fn&& fn)
{
if (base.tag_value == Candidate::tag)
{
return std::forward<Fn>(fn)(static_cast<Candidate&>(base));
}
if constexpr (sizeof...(Candidates) > 0)
{
return apply_casted<Candidates...>(base, std::forward<Fn>(fn));
}
else
{
throw std::runtime_error{"tag_value doesn't match"};
}
}
DEMO
If the return types can differ, a common one should be specified as a result of apply_casted:
std::common_type_t<std::invoke_result_t<Fn, Candidate&>
, std::invoke_result_t<Fn, Candidates&>...>
A similar functionality can be achieved with std::variant:
template <typename... Ts> struct overload : Ts... { using Ts::operator()...; };
template <typename... Ts> overload(Ts...) -> overload<Ts...>;
std::variant<Derived1, Derived2, Derived3> v;
v.emplace<Derived2>();
std::visit(overload{ [](Derived2& d) -> int { return d.foo(); },
[](auto& d) -> int { throw std::runtime_error{""}; } }, v);
DEMO 2
For a better performance, you should use a jump table, similar to the below one:
template <typename R, typename F, typename V, typename C>
struct invoker
{
static R invoke(F&& f, V&& v)
{
return f(static_cast<C&&>(v));
}
};
template <typename Candidate, typename... Candidates, typename Fn>
auto apply_casted(Base& base, Fn&& fn)
{
using R = std::common_type_t<std::invoke_result_t<Fn, Candidate&>
, std::invoke_result_t<Fn, Candidates&>...>;
using invoker_t = R(*)(Fn&&, Base&);
invoker_t arr[]{ &invoker<R, Fn, Base&, Candidate&>::invoke
, &invoker<R, Fn, Base&, Candidates&>::invoke... };
return arr[base.tag_value](std::forward<Fn>(fn), base);
}
DEMO 3
It's too late too play?
You tagged C++17, so you can use template folding (modified following a Frank's suggestion (thanks!))
template <class ... Candidates, class Fn>
auto apply_casted(Base & base, Fn fn)
{
int ret {-1};
if ( false == ((Candidates::tag == base.tag_value
? ret = fn(static_cast<Candidates&>(base)), true
: false) || ...) )
; // throw something
return ret;
}
Related
I have a template function:
template<typename R, typename... T>
void function(const std::string& id, R (*f)(T...)) {
switch (sizeof...(T)) {
case 0: f0compile<R>(reinterpret_cast<void (*)()>(f)); break;
case 1: f1compile<R, T>(reinterpret_cast<void (*)()>(f)); break;
case 2: f2compile<R, T1, T2>(reinterpret_cast<void (*)()>(f)); break;
}
...
}
How can I call these functions (f0compile, f1compile, f2compile) ? How can I write the "function" ?
template<typename R>
void f0compile(void (*f)()) {
new F0<R>(f):
...
}
template<typename R, typename T>
void f1compile(void (*f)()) {
new F1<R,T>(f);
...
}
template<typename R, typename T1, typename T2>
void f2compile(void (*f)()) {
new F2<R,T1,T2>(f);
...
}
Thank you for help with these variadic template.
I add the implementation of F0 F1 F2:
template <typename R> struct F0 : F {
F0(void (*_fn)()) : F(typeid(R))
, fn(reinterpret_cast<R(*)()>(_fn))
{}
const void* f() { res = fn(); return &res; }
R res; R (*fn)();
void d() { delete this; }
};
template <typename R, typename T> struct F1 : F {
F1(void (*_fn)(), F* _opd) : F(typeid(R))
, fn(reinterpret_cast<R(*)(T)>(_fn))
, opd(autocast<T>(_opd))
{}
const void* f() { res = fn(*(T*) opd->f()); return &res; }
F* opd;
R res; R (*fn)(T);
void d() { opd->d(); delete this; }
};
template <typename R, typename T1, typename T2> struct F2 : F {
F2(void (*_fn)(), F* _opd1, F* _opd2) : F(typeid(R))
, fn(reinterpret_cast<R(*)(T1,T2)>(_fn))
, opd1(autocast<T1>(_opd1))
, opd2(autocast<T2>(_opd2))
{}
const void* f() { res = fn(*(T1*) opd1->f(), *(T2*) opd2->f()); return &res; }
F* opd1; F* opd2;
R res; R (*fn)(T1,T2);
void d() { opd1->d(); opd2->d(); delete this; }
};
Thank you
struct F {
F(const std::type_info& _type) : type(_type) {}
virtual ~F() {}
const std::type_info& type;
virtual const void* f() = 0;
virtual void d() = 0;
};
Added class F . It rapresent each function / operand on the stack
template <typename T> struct Opd : F {
Opd(T _opd) : F(typeid(T)), res(_opd) { }
const void* f() { return &res; }
T res;
void d() { delete this; }
};
Added class Opd . It represent a specific operand on the stack.
The real program is this (simplified):
double foo(double op1, double op2) {
return op1 + op2;
}
#include <functional>
#include <stack>
#include <type_traits>
class Expression {
public:
struct F {
F(const std::type_info& _type) : type(_type) {}
virtual ~F() {}
const std::type_info& type;
virtual const void* f() = 0;
virtual void d() = 0;
};
public:
Expression() : m_cexpr(NULL) {}
~Expression() {
if (m_cexpr) m_cexpr->d();
}
// function
template<typename R, typename... T> void function(R (*f)(T...), void (*compile)(void (*)(), std::stack<F*>&)) {
m_f = std::make_pair(reinterpret_cast<void (*)()>(f), compile);
}
template<typename R, typename T1, typename T2> static void f2compile(void (*f)(), std::stack<F*>& s) {
auto opd2 = s.top();
s.pop();
auto opd1 = s.top();
s.pop();
s.push(new F2<R,T1,T2>(f, opd1, opd2));
}
void compile() {
if (m_cexpr) m_cexpr->d();
std::stack<F*> s;
s.push(new Opd<double>(1));
s.push(new Opd<double>(2));
m_f.second(m_f.first, s);
m_cexpr = s.top();
s.pop();
assert(s.empty());
}
void* execute() {
return const_cast<void*>(m_cexpr->f());
}
const std::type_info& type() {
return m_cexpr->type;
}
private:
F* m_cexpr;
std::pair<void (*)(), void (*)(void (*)(), std::stack<F*>&)> m_f;
template <typename T> struct Opd : F {
Opd(T _opd) : F(typeid(T)), res(_opd) {}
const void* f() { return &res; }
T res;
void d() { delete this; }
};
template <typename R, typename T1, typename T2> struct F2 : F {
F2(void (*_fn)(), F* _opd1, F* _opd2) : F(typeid(R))
, fn(reinterpret_cast<R(*)(T1,T2)>(_fn))
, opd1(_opd1)
, opd2(_opd2)
{}
const void* f() { res = fn(*(T1*) opd1->f(), *(T2*) opd2->f()); return &res; }
F* opd1; F* opd2;
R res; R (*fn)(T1,T2);
void d() { opd1->d(); opd2->d(); delete this; }
};
};
TEST_CASE("expression") {
Expression e;
e.function(foo, e.f2compile<double, double, double>);
e.compile();
e.execute();
REQUIRE(e.type() == typeid(double));
REQUIRE(*static_cast<double*>(e.execute()) == 3);
}
And my problem is how write better code c++11 using variadic template. How write a function "fNcompile" and a function "FN" with variadic template.
I don't think you need the variadic template. Instead:
template<typename R>
void fcompile(void (*f)()) {
new F0<R>(reinterpret_cast<void (*)()>(f));
...
}
template<typename R, typename T>
void fcompile(void (*f)(T)) {
new F1<R,T>(reinterpret_cast<void (*)()>(f));
...
}
template<typename R, typename T1, typename T2>
void fcompile(void (*f)(T1, T2)) {
new F1<R,T1,T2>(reinterpret_cast<void (*)()>(f));
...
}
Now you can call fcompile<some_type>(some_func) for any some_type and any nullary/unary/binary some_func which returns void.
To answer the specific question, below are variadic FN and fNcompile as close as possible to your existing code. First, though, since you said you're working in C++11, we'll need an equivalent of std::make_index_sequence from C++14. Here's a simple one. You can search for others that are smarter about being less likely to hit compiler template limitations...
namespace cxx_compat {
template <typename T, T... Values>
struct integer_sequence {
static constexpr std::size_t size() const
{ return sizeof...(Values); }
};
template <typename T, T Smallest, T... Values>
struct make_integer_sequence_helper {
static_assert(Smallest > 0,
"make_integer_sequence argument must not be negative");
using type = typename make_integer_sequence_helper<
T, Smallest-1, Smallest-1, Values...>::type;
};
template <typename T, T... Values>
struct make_integer_sequence_helper<T, 0, Values...> {
using type = integer_sequence<T, Values...>;
};
template <typename T, T N>
using make_integer_sequence =
typename make_integer_sequence_helper<T, N>::type;
template <std::size_t... Values>
using index_sequence = integer_sequence<std::size_t, Values...>;
template <std::size_t N>
using make_index_sequence = make_integer_sequence<std::size_t, N>;
template <typename... T>
using index_sequence_for = make_index_sequence<sizeof...(T)>;
} // end namespace cxx_compat
And now, the actual FN and fNcompile:
template <typename R, typename ...T> struct FN : F {
private:
template <typename T>
using any_to_Fstar = F*;
public:
FN(void (*_fn)(), any_to_Fstar<T> ... _opd) : F(typeid(R))
, fn(reinterpret_cast<R(*)(T...)>(_fn))
, opd{_opd...}
{}
FN(R (*_fn)(T...)) : F(typeid(R)), fn(_fn), opd() {}
const void* f() {
f_helper(cxx_compat::index_sequence_for<T...>{});
return &res;
}
std::array<F*, sizeof...(T)> opd;
R res; R (*fn)(T...);
void d() {
for (F* o : opd)
o->d();
delete this;
}
private:
template <std::size_t... Inds>
void f_helper(cxx_compat::index_sequence<Inds...>)
{ res = fn(*(T*) opd[Inds]->f() ...); }
};
template<typename R, typename... T>
static void fNcompile(void (*f)(), std::stack<F*>& s) {
auto* f_obj = new FN<R, T...>(f);
for (std::size_t ind = sizeof...(T); ind > 0;) {
f_obj->opd[--ind] = s.top();
s.pop();
}
s.push(f_obj);
}
What's going on:
To actually call the function pointer, we need access to a number of function arguments at the same time, so to replace the named members opd1, opd2 with a number of F* pointers determined by template instantiation, we use a std::array<F*, sizeof...(T)>, since sizeof...(T) is the number of argument types provided to the template.
For compatibility with the F2 constructor you declared, any_to_Fstar<T> ... _opd declares a number of constructor parameters to match the number of T template arguments, all with the same type F*. (But now fNcompile uses the additional constructor taking just the function pointer instead, and sets the array members afterward.)
To get at these pointers and pass them all to fn in one expression, we need to expand some sort of variadic pack. Here's where index_sequence comes in:
index_sequence_for<T...> is a type alias for index_sequence with a sequence of numbers counting up from zero as template arguments. For example, if sizeof...(T) is 4, then index_sequence_for<T...> is index_sequence<0, 1, 2, 3>.
f just calls a private function f_helper, passing it an object of that index_sequence_for<T...> type.
The compiler can deduce the template argument list for f_helper from matching the index_sequence types: Inds... must be that same sequence of numbers counting up from zero.
In the f_helper body, the expression fn(*(T*) opd[Inds]->f() ...) is instantiated by expanding both the template parameter packs T and Inds to get one list of function arguments for calling fn.
However, use of void pointers and reinterpret_cast is dangerous and rarely actually necessary in C++. There's almost always a safer way using templates. So I'd redesign this to be something more like:
#include <type_traits>
#include <typeinfo>
#include <stdexcept>
#include <memory>
#include <stack>
namespace cxx_compat {
// Define integer_sequence and related templates as above.
template <typename T, typename... Args>
std::unique_ptr<T> make_unique(Args&& ... args)
{
return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
}
} // end namespace cxx_compat
class bad_expression_type : public std::logic_error
{
public:
bad_expression_type(const std::type_info& required,
const std::type_info& passed)
: logic_error("bad_argument_type"),
required_type(required),
passed_type(passed) {}
const std::type_info& required_type;
const std::type_info& passed_type;
};
class Expression
{
public:
class F
{
public:
F() noexcept = default;
F(const F&) = delete;
F& operator=(const F&) = delete;
virtual ~F() = default;
virtual const std::type_info& type() const noexcept = 0;
virtual void compile(std::stack<std::unique_ptr<F>>&) = 0;
template <typename R>
R call_R() const;
};
using F_ptr = std::unique_ptr<F>;
using F_stack = std::stack<F_ptr>;
template <typename R>
class Typed_F : public F
{
public:
const std::type_info& type() const noexcept override
{ return typeid(R); }
virtual R call() const = 0;
};
// Accepts any callable: function pointer, lambda, std::function,
// other class with operator().
template <typename R, typename... T, typename Func,
typename = typename std::enable_if<std::is_convertible<
decltype(std::declval<const Func&>()(std::declval<T>()...)),
R>::value>::type>
void function(Func func)
{
store_func<R, T...>(std::move(func));
}
// Overload for function pointer that does not need explicit
// template arguments:
template <typename R, typename... T>
void function(R (*fptr)(T...))
{
store_func<R, T...>(fptr);
}
template <typename T>
void constant(const T& value)
{
store_func<T>([value](){ return value; });
}
void compile(F_stack& stack)
{
m_cexpr->compile(stack);
}
private:
template <typename Func, typename R, typename... T>
class F_Impl : public Typed_F<R>
{
public:
F_Impl(Func func) : m_func(std::move(func)) {}
void compile(F_stack& stack) override {
take_args_helper(stack, cxx_compat::index_sequence_for<T...>{});
}
R call() const override {
return call_helper(cxx_compat::index_sequence_for<T...>{});
}
private:
template <typename Arg>
int take_one_arg(std::unique_ptr<Typed_F<Arg>>& arg, F_stack& stack)
{
auto* fptr = dynamic_cast<Typed_F<Arg>*>(stack.top().get());
if (!fptr)
throw bad_expression_type(
typeid(Arg), stack.top()->type());
arg.reset(fptr);
stack.top().release();
stack.pop();
return 0;
}
template <std::size_t... Inds>
void take_args_helper(F_stack& stack, cxx_compat::index_sequence<Inds...>)
{
using int_array = int[];
(void) int_array{ take_one_arg(std::get<Inds>(m_args), stack) ..., 0 };
}
template <std::size_t... Inds>
R call_helper(cxx_compat::index_sequence<Inds...>) const {
return m_func(std::get<Inds>(m_args)->call()...);
}
Func m_func;
std::tuple<std::unique_ptr<Typed_F<T>>...> m_args;
};
template <typename R, typename... T, typename Func>
void store_func(Func func)
{
m_cexpr = cxx_compat::make_unique<F_Impl<Func, R, T...>>(
std::move(func));
}
F_ptr m_cexpr;
};
template <typename R>
R Expression::F::call_R() const
{
auto* typed_this = dynamic_cast<const Typed_F<R>*>(this);
if (!typed_this)
throw bad_expression_type(typeid(R), type());
return typed_this->call();
}
TEST_CASE("expression") {
Expression a;
a.constant(1.0);
Expression b;
b.constant(2.0);
Expression c;
c.function(+[](double x, double y) { return x+y; });
Expression::F_stack stack;
a.compile(stack);
REQUIRE(stack.size() == 1);
b.compile(stack);
REQUIRE(stack.size() == 2);
c.compile(stack);
REQUIRE(stack.size() == 1);
REQUIRE(stack.top() != nullptr);
REQUIRE(stack.top()->type() == typeid(double));
REQUIRE(stack.top()->call_R<double>() == 3.0);
}
It would also be possible, but a bit tricky, to support reference and const variations of the argument and result types, for example, using a std::string(*)() function as an argument to an unsigned int(*)(const std::string&) function.
My question here is similar to this post expect that I have more than one template argument and string. Thus, the setup is
class base_class; // no template args
template<typename T, typename U, typename V>
class child_class : public base_class;
I have a limited number of implemented types for T, U and V which I want to select at runtime given three strings. So as the question in cited post, I could do something like
std::unique_ptr<base_class> choose_arg1(
std::string T_str, std::string U_str, std::string v_str){
if(T_str == "int"){
return(choose_arg2<int>(U_str, V_str));
} else if(T_str == "char"){
return(choose_arg2<char>(U_str, V_str));
} // ...
}
template<typename T>
std::unique_ptr<base_class> choose_arg2(std::string U_str, std::string v_str){
if(U_str == "int"){
return(choose_arg3<T, int>(V_str));
} else if(U_str == "char"){
return(choose_arg3<T, char>(V_str));
} // ...
}
template<typename T, typename U>
std::unique_ptr<base_class> choose_arg3(std::string v_str){
if(v_str == "int"){
return(std::make_unique<child_class<T, U, int>>());
} else if(v_str == "char"){
return(std::make_unique<child_class<T, U, char>>());
} // ...
}
but is there a better way? I have less than 5^3 combination for the record.
I suggest to develop a template helper struct with a couple of static func() methods
template <typename ... Ts>
struct choose_args_h
{
using retT = std::unique_ptr<base_class>;
template <typename ... Args>
static retT func (std::string const & s, Args const & ... args)
{
if ( s == "int" )
return choose_args_h<Ts..., int>::func(args...);
else if ( s == "char" )
return choose_args_h<Ts..., char>::func(args...);
// else ...
}
static retT func ()
{ return std::make_unique<child_class<Ts...>>(); }
};
so you can write a choose_args() func simply as follows
template <typename ... Args>
std::unique_ptr<base_class> choose_args (Args const & ... args)
{ return choose_args_h<>::func(args...); }
The following is a full working example
#include <string>
#include <memory>
class base_class
{ };
template <typename, typename, typename>
class child_class : public base_class
{ };
template <typename ... Ts>
struct choose_args_h
{
using retT = std::unique_ptr<base_class>;
template <typename ... Args>
static retT func (std::string const & s, Args const & ... args)
{
if ( s == "int" )
return choose_args_h<Ts..., int>::func(args...);
else if ( s == "char" )
return choose_args_h<Ts..., char>::func(args...);
// else ...
}
static retT func ()
{ return std::make_unique<child_class<Ts...>>(); }
};
template <typename ... Args>
std::unique_ptr<base_class> choose_args (Args const & ... args)
{ return choose_args_h<>::func(args...); }
int main ()
{
auto p0 = choose_args("int", "char", "int");
auto p1 = choose_args("int", "char", "char");
}
Shown in this post is a C++17 solution with compile-time configuration of the allowed types and corresponding keys via the type Argmaps. The lookup is done by a compile-time loop.
C++11 does not support generic lambdas which are required for the compile-time loops used here. Instead, one could perform the lookup by template meta-programming with the "indices trick" (as in this online demo), but that feels too complicated and I prefer the std::map approach anyway. Note that my linked C++11 attempt could call the constructor twice if the keys are not unique.
#include <iostream>
#include <memory>
#include <string>
#include "loop.hpp"
template<class... Ts> struct Types {
static constexpr size_t size = sizeof...(Ts);
template<size_t i>
using At = std::tuple_element_t<i, std::tuple<Ts...>>;
};
template<class... Ts> constexpr Types<Ts...> to_types(Ts...) { return {}; }
template<auto... cs> struct Str {
operator std::string() const {
constexpr auto list = std::initializer_list<char>{cs...};
return std::string{list.begin(), list.end()};
}
};
template<class Char, Char... cs>
constexpr auto operator""_c() {
return Str<cs...>{};
}
//////////////////////////////////////////////////////////////////////////////
struct Base {
virtual void identify() const = 0;
};
template<class... Ts>
struct Derived : Base {
virtual void identify() const override {
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
};
using Ptr = std::unique_ptr<Base>;
//////////////////////////////////////////////////////////////////////////////
template<class Argmaps, class Args=Types<>>
struct choose_impl;
template<class Map0, class... Maps, class... Args>
struct choose_impl<Types<Map0, Maps...>, Types<Args...>> {
static constexpr size_t pos = sizeof...(Args);
template<class S0, class... Ss>
static Ptr get(S0 s0, Ss... ss) {
Ptr ret{nullptr};
using namespace Loop;
loop(less<Map0::size>, [&] (auto i) {
using Argmapping = typename Map0::template At<i>;
using Key = typename Argmapping::template At<0>;
using Arg = typename Argmapping::template At<1>;
using Recursion = choose_impl<Types<Maps...>, Types<Args..., Arg>>;
if(std::string(Key{}) == s0) ret = Recursion::get(ss...);
});
if(!ret) {
std::cerr << "NOT MAPPED AT POS " << pos << ": " << s0 << std::endl;
std::terminate();
}
return ret;
}
};
template<class... Args>// all Args are resolved
struct choose_impl<Types<>, Types<Args...>> {
static Ptr get() {
return std::make_unique<Derived<Args...>>();
}
};
template<class Argmaps, class... Ss>
Ptr choose(Ss... ss) {
static_assert(Argmaps::size == sizeof...(Ss));
return choose_impl<Argmaps>::get(std::string(ss)...);
}
template<class V, class K>
auto make_argmapping(K) {
return Types<K, V>{};
}
//////////////////////////////////////////////////////////////////////////////
int main() {
using Argmaps = decltype(
to_types(
to_types(// first template parameter
make_argmapping<int>("int"_c),
make_argmapping<char>("char"_c),
make_argmapping<bool>("bool"_c)
),
to_types(// ... second ...
make_argmapping<double>("double"_c),
make_argmapping<long>("long"_c)
),
to_types(// ... third
make_argmapping<bool>("bool"_c)
)
)
);
choose<Argmaps>("int", "double", "bool")->identify();
choose<Argmaps>("int", "long", "bool")->identify();
choose<Argmaps>("char", "double", "bool")->identify();
choose<Argmaps>("char", "long", "bool")->identify();
choose<Argmaps>("bool", "double", "bool")->identify();
choose<Argmaps>("bool", "long", "bool")->identify();
// bad choice:
choose<Argmaps>("int", "int", "bool")->identify();
return 0;
}
loop.hpp from this unread answer:
#ifndef LOOP_HPP
#define LOOP_HPP
namespace Loop {
template<auto v> using Val = std::integral_constant<decltype(v), v>;
template<auto i> struct From : Val<i> {};
template<auto i> static constexpr From<i> from{};
template<auto i> struct Less : Val<i> {};
template<auto i> static constexpr Less<i> less{};
// `to<i>` implies `less<i+1>`
template<auto i> struct To : Less<i+decltype(i)(1)> {};
template<auto i> static constexpr To<i> to{};
template<auto i> struct By : Val<i> {};
template<auto i> static constexpr By<i> by{};
template<auto i, auto N, auto delta, class F>
constexpr void loop(From<i>, Less<N>, By<delta>, F f) noexcept {
if constexpr(i<N) {
f(Val<i>{});
loop(from<i+delta>, less<N>, by<delta>, f);
}
}
// overload with two arguments (defaulting `by<1>`)
template<auto i, auto N, class F>
constexpr void loop(From<i>, Less<N>, F f) noexcept {
loop(from<i>, less<N>, by<decltype(i)(1)>, f);
}
// overload with two arguments (defaulting `from<0>`)
template<auto N, auto delta, class F>
constexpr void loop(Less<N>, By<delta>, F f) noexcept {
loop(from<decltype(N)(0)>, less<N>, by<delta>, f);
}
// overload with one argument (defaulting `from<0>`, `by<1>`)
template<auto N, class F>
constexpr void loop(Less<N>, F f) noexcept {
using Ind = decltype(N);
loop(from<Ind(0)>, less<N>, by<Ind(1)>, f);
}
} // namespace Loop
#endif
http://coliru.stacked-crooked.com/a/5ce61617497c3bbe
As I noted in my comment, you could use a static map of string to function.
For your example code (slightly simplified to 2 template parameters to make it a little shorter), this would become:
#include <iostream>
#include <string>
#include <map>
#include <functional>
#include <memory>
class base_class { }; // no template args
template<typename T, typename U>
class child_class : public base_class { };
using ptr_type = std::unique_ptr<base_class>;
// Declarations
std::unique_ptr<base_class> choose_arg1 (std::string const & T_str,
std::string const & U_str);
template<typename T>
std::unique_ptr<base_class> choose_arg2 (std::string const & U_str);
// Definitions
std::unique_ptr<base_class> choose_arg1 (std::string const & T_str,
std::string const & U_str) {
using function_type = std::function<ptr_type(std::string const &)>;
using map_type = std::map<std::string, function_type>;
static const map_type ptrMap = {
{"int", choose_arg2<int> },
{"char", choose_arg2<char> }
};
auto ptrIter = ptrMap.find(T_str);
return (ptrIter != ptrMap.end()) ? ptrIter->second(U_str) : nullptr;
}
template<typename T>
std::unique_ptr<base_class> choose_arg2 (std::string const & U_str) {
using function_type = std::function<ptr_type()>;
using map_type = std::map<std::string, function_type>;
static const map_type ptrMap = {
{"int", []{ return std::make_unique<child_class<T, int>>(); } },
{"char", []{ return std::make_unique<child_class<T, char>>(); } }
};
auto ptrIter = ptrMap.find(U_str);
return (ptrIter != ptrMap.end()) ? ptrIter->second() : nullptr;
}
int main () {
std::cout << typeid(choose_arg1("int", "char")).name() << "\n";
std::cout << "[Done]\n";
}
I want to implement a polymorphic visitor using lambdas without implementing a class. I already have a foundation but am struggling with the type deduction for the parameters of my lambdas.
Let's say I have some legacy code base that decided to use type tags for a polymorphic type like so:
enum class ClassType
{
BaseType = 0, TypeA, TypeB
};
class BaseType
{
public:
virtual ~BaseType() {}
ClassType getType() const
{ return type; }
protected:
ClassType type;
};
class TypeA : public BaseType
{
public:
static const ClassType Type = ClassType::TypeA;
explicit TypeA(int val) : val(val)
{ type = ClassType::TypeA; }
virtual ~TypeA() {}
int val;
};
class TypeB : public BaseType
{
public:
static const ClassType Type = ClassType::TypeB;
explicit TypeB(std::string s) : s(s)
{ type = ClassType::TypeB; }
virtual ~TypeB() {}
std::string s;
};
What I want to achieve is a visitor similar to the std::variant visitors that would then look like this:
std::vector<BaseType*> elements;
elements.emplace_back(new TypeA(1));
elements.emplace_back(new TypeB("hello"));
for (auto elem : elements)
{
visit(elem,
[](TypeA* typeA) {
std::cout << "Found TypeA element, val=" << typeA->val << std::endl;
},
[](TypeB* typeB) {
std::cout << "Found TypeB element, s=" << typeB->s << std::endl;
}
);
}
My so far failing approach for implementing such a visit<>() function was the following code:
template <typename T>
struct identity
{
typedef T type;
};
template <typename T>
void apply_(BaseType* b, typename identity<std::function<void(T*)>&>::type visitor)
{
if (b->getType() != T::Type)
return;
T* t = dynamic_cast<T*>(b);
if (t) visitor(t);
}
template <typename... Ts>
void visit(BaseType* b, Ts... visitors) {
std::initializer_list<int>{ (apply_(b, visitors), 0)... };
}
The compiler complains that it cannot deduce the template parameter T for my apply_ function.
How can I declare the correct template and function signature of apply_ to correctly capture lambdas and maybe even other callables? Or is something like this even possible at all?
Here's an (incomplete) solution that works with any function object that has an unary, non-overloaded, non-templated operator(). Firstly, let's create an helper type alias to retrieve the type of the first argument:
template <typename>
struct deduce_arg_type;
template <typename Return, typename X, typename T>
struct deduce_arg_type<Return(X::*)(T) const>
{
using type = T;
};
template <typename F>
using arg_type = typename deduce_arg_type<decltype(&F::operator())>::type;
Then, we can use a fold expression in a variadic template to call any function object for which dynamic_cast succeeds:
template <typename Base, typename... Fs>
void visit(Base* ptr, Fs&&... fs)
{
const auto attempt = [&](auto&& f)
{
using f_type = std::decay_t<decltype(f)>;
using p_type = arg_type<f_type>;
if(auto cp = dynamic_cast<p_type>(ptr); cp != nullptr)
{
std::forward<decltype(f)>(f)(cp);
}
};
(attempt(std::forward<Fs>(fs)), ...);
}
Usage example:
int main()
{
std::vector<std::unique_ptr<Base>> v;
v.emplace_back(std::make_unique<A>());
v.emplace_back(std::make_unique<B>());
v.emplace_back(std::make_unique<C>());
for(const auto& p : v)
{
visit(p.get(), [](const A*){ std::cout << "A"; },
[](const B*){ std::cout << "B"; },
[](const C*){ std::cout << "C"; });
}
}
ABC
live example on wandbox
Assuming that you cannot change the virtual classes, you may do the following:
template <typename F>
decltype(auto) visitBaseType(BaseType& base, F&& f)
{
switch (base.getType())
{
case ClassType::BaseType: return f(base);
case ClassType::TypeA: return f(dynamic_cast<TypeA&>(base));
case ClassType::TypeB: return f(dynamic_cast<TypeB&>(base));
}
throw std::runtime_error("Bad type");
}
template<class... Ts> struct overloaded : Ts... {
using Ts::operator()...;
overloaded(Ts... ts) : Ts(ts)... {}
};
template<class... Ts> overloaded(Ts...) -> overloaded<Ts...>;
template <typename ... Fs>
decltype(auto) visit(BaseType& base, Fs&&... fs)
{
return visitBaseType(base, overloaded(fs...));
}
Demo
I don't always say this, but this may be a job for the Boost.Preprocessor. You have a list of class types that corresponds to a list of enums, each instance identifies itself via getType(). So we can use that:
#include <boost/preprocessor/seq/for_each.hpp>
#define CLASS_LIST (TypeA) (TypeB)
// just take one visitor
template <class Visitor>
void visit(Base* ptr, Visitor f) {
switch (ptr->getType()) {
#define CASE_ST(r, data, elem) case elem: f(static_cast<elem*>(ptr)); break;
BOOST_PP_SEQ_FOR_EACH(CASE_ST, ~, CLASS_LIST)
#undef CASE_ST
default: f(ptr); // in case you want an "else"
// this is optional
}
}
That will preprocess into:
switch (ptr->getType()) {
case TypeA: f(static_cast<TypeA*>(ptr)); break;
case TypeB: f(static_cast<TypeB*>(ptr)); break;
default: f(ptr);
}
Be warned: There's a lot of background info here before we get to the real question.
I have a fairly wide C++ class hierarchy (representing something like expressions of different types):
class BaseValue { virtual ~BaseValue(); };
class IntValue final : public BaseValue { int get() const; };
class DoubleValue final : public BaseValue { double get() const; };
class StringValue final : public BaseValue { std::string get() const; };
And on the other side, I have a way to coerce the user's input to an expected type:
class UserInput { template<class T> get_as() const; };
So one way to write a matcher — "does the user's input equal this BaseValue's value?" — would be like this:
class BaseValue { virtual bool is_equal(UserInput) const; };
class IntValue : public BaseValue {
int get() const;
bool is_equal(UserInput u) const override {
return u.get_as<int>() == get();
}
};
// and so on, with overrides for each child class...
bool does_equal(BaseValue *bp, UserInput u) {
return bp->is_equal(u);
}
However, this doesn't scale, either in the "width of the hierarchy" direction, or in the "number of operations" direction. For example, if I want to add bool does_be_greater(BaseValue*, UserInput), that would require a whole nother virtual method with N implementations scattered across the hierarchy. So I decided to go this route instead:
bool does_equal(BaseValue *bp, UserInput u) {
if (typeid(*bp) == typeid(IntValue)) {
return static_cast<IntValue*>(bp)->get() == u.get_as<int>();
} else if (typeid(*bp) == typeid(DoubleValue)) {
return static_cast<DoubleValue*>(bp)->get() == u.get_as<double>();
...
} else {
throw Oops();
}
}
In fact, I can do some metaprogramming and collapse that down into a single function visit taking a generic lambda:
bool does_equal(BaseValue *bp, UserInput u) {
my::visit<IntValue, DoubleValue, StringValue>(*bp, [&](const auto& dp){
using T = std::decay_t<decltype(dp.get())>;
return dp.get() == u.get_as<T>();
});
}
my::visit is implemented as a "recursive" function template: my::visit<A,B,C> simply tests typeid against A, calls the lambda if so, and calls my::visit<B,C> if not. At the bottom of the call stack, my::visit<C> tests typeid against C, calls the lambda if so, and throws Oops() if not.
Okay, now for my actual question!
The problem with my::visit is that the on-error behavior "throw Oops()" is hard-coded. I'd really prefer to have the error behavior be user-specified, like this:
bool does_be_greater(BaseValue *bp, UserInput u) {
my::visit<IntValue, DoubleValue, StringValue>(*bp, [&](const auto& dp){
using T = std::decay_t<decltype(dp.get())>;
return dp.get() > u.get_as<T>();
}, [](){
throw Oops();
});
}
The problem I'm having is, when I do that, I can't figure out how to implement the base class in such a way that the compiler will shut up about either mismatched return types or falling off the end of a function! Here's the version without an on_error callback:
template<class Base, class F>
struct visit_impl {
template<class DerivedClass>
static auto call(Base&& base, const F& f) {
if (typeid(base) == typeid(DerivedClass)) {
using Derived = match_cvref_t<Base, DerivedClass>;
return f(std::forward<Derived>(static_cast<Derived&&>(base)));
} else {
throw Oops();
}
}
template<class DerivedClass, class R, class... Est>
static auto call(Base&& base, const F& f) {
[...snip...]
};
template<class... Ds, class B, class F>
auto visit(B&& base, const F& f) {
return visit_impl<B, F>::template call<Ds...>( std::forward<B>(base), f);
}
And here's what I'd really like to have:
template<class Base, class F, class E>
struct visit_impl {
template<class DerivedClass>
static auto call(Base&& base, const F& f, const E& on_error) {
if (typeid(base) == typeid(DerivedClass)) {
using Derived = match_cvref_t<Base, DerivedClass>;
return f(std::forward<Derived>(static_cast<Derived&&>(base)));
} else {
return on_error();
}
}
template<class DerivedClass, class R, class... Est>
static auto call(Base&& base, const F& f, const E& on_error) {
[...snip...]
};
template<class... Ds, class B, class F, class E>
auto visit(B&& base, const F& f, const E& on_error) {
return visit_impl<B, F>::template call<Ds...>( std::forward<B>(base), f, on_error);
}
That is, I want to be able to handle both of these cases:
template<class... Ds, class B, class F>
auto visit_or_throw(B&& base, const F& f) {
return visit<Ds...>(std::forward<B>(base), f, []{
throw std::bad_cast();
});
}
template<class... Ds, class B>
auto is_any_of(B&& base) {
return visit<Ds...>(std::forward<B>(base),
[]{ return true; }, []{ return false; });
}
So I guess one way to do it would be write several specializations of the base case:
when is_void_v<decltype(on_error())>, use {on_error(); throw Dummy();} to silence the compiler warning
when is_same_v<decltype(on_error()), decltype(f(Derived{}))>, use {return on_error();}
otherwise, static-assert
But I feel like I'm missing some simpler approach. Can anyone see it?
I guess one way to do it would be write several specializations of the base case
Instead of doing that, you could isolate your "compile-time branches" to a function that deals exclusively with calling on_error, and call that new function instead of on_error inside visit_impl::call.
template<class DerivedClass>
static auto call(Base&& base, const F& f, const E& on_error) {
if (typeid(base) == typeid(DerivedClass)) {
using Derived = match_cvref_t<Base, DerivedClass>;
return f(std::forward<Derived>(static_cast<Derived&&>(base)));
} else {
return error_dispatch<F, Derived>(on_error);
// ^^^^^^^^^^^^^^^^^^^^^^^^^
}
}
template <typename F, typename Derived, typename E>
auto error_dispatch(const E& on_error)
-> std::enable_if_t<is_void_v<decltype(on_error())>>
{
on_error();
throw Dummy();
}
template <typename F, typename Derived, typename E>
auto error_dispatch(const E& on_error)
-> std::enable_if_t<
is_same_v<decltype(on_error()),
decltype(std::declval<const F&>()(Derived{}))>
>
{
return on_error();
}
How about using variant (std C++17, or boost one)? (and use static visitor)
using BaseValue = std::variant<int, double, std::string>;
struct bin_op
{
void operator() (int, double) const { std::cout << "int double\n"; }
void operator() (const std::string&, const std::string&) const
{ std::cout << "strings\n"; }
template <typename T1, typename T2>
void operator() (const T1&, const T2&) const { std::cout << "other\n"; /* Or throw */ }
};
int main(){
BaseValue vi{42};
BaseValue vd{42.5};
BaseValue vs{std::string("Hello")};
std::cout << (vi == vd) << std::endl;
std::visit(bin_op{}, vi, vd);
std::visit(bin_op{}, vs, vs);
std::visit(bin_op{}, vi, vs);
}
Demo
I'm trying to implement a container class for different functions where I can hold function pointers and use it to call those functions later. I'll try to discribe my problem more accurate.
As example, I have 2 different test functions:
int func1(int a, int b) {
printf("func1 works! %i %i\n", a, b);
return 0;
}
void func2(double a, double b) {
printf("func2 works! %.2lf %.2lf\n", a, b);
}
and I also have array of variants, which holds function arguments:
std::vector<boost::variant<int, double>> args = {2.2, 3.3};
I've decided to use my own functor class derived from some base class ( I thought about using virtual methods):
class BaseFunc {
public:
BaseFunc() {}
~BaseFunc() {}
};
template <typename T>
class Func;
template <typename R, typename... Tn>
class Func<R(Tn...)> : public BaseFunc {
typedef R(*fptr_t)(Tn...);
fptr_t fptr;
public:
Func() : fptr(nullptr) {}
Func(fptr_t f) : fptr(f) {}
R operator()(Tn... args) {
return fptr(args...);
}
Func& operator=(fptr_t f) {
fptr = f;
return *this;
}
};
Also I've decided to store some information about function and its arguments:
struct TypeInfo {
int type_id; // for this example: 0 - int, 1 - double
template <class T>
void ObtainType() {
if (std::is_same<void, T>::value)
type_id = 0;
else if (std::is_same<int, T>::value)
type_id = 1;
else if (std::is_same<double, T>::value)
type_id = 2;
else
type_id = -1;
}
};
struct FunctionInfo {
public:
FunctionInfo() {}
FunctionInfo(BaseFunc *func, const TypeInfo& ret, std::vector<TypeInfo>& args) :
func_ptr(func), return_info(ret)
{
args_info.swap(args);
}
~FunctionInfo() {
delete func_ptr;
}
BaseFunc * func_ptr;
TypeInfo return_info;
std::vector<TypeInfo> args_info;
};
So now I can define a container class:
class Container {
private:
template <size_t n, typename... T>
void ObtainTypeImpl(size_t i, TypeInfo& t)
{
if (i == n)
t.ObtainType<std::tuple_element<n, std::tuple<T...>>::type>();
else if (n == sizeof...(T)-1)
throw std::out_of_range("Tuple element out of range.");
else
ObtainTypeImpl<(n < sizeof...(T)-1 ? n + 1 : 0), T...>(i, t);
}
template <typename... T>
void ObtainType(size_t i, TypeInfo& t)
{
return ObtainTypeImpl<0, T...>(i, t);
}
public:
template <class R, class ...Args>
void AddFunc(const std::string& str, R(*func)(Args...)) {
BaseFunc * func_ptr = new Func<R(Args...)>(func);
size_t arity = sizeof...(Args);
TypeInfo ret;
ret.ObtainType<R>();
std::vector<TypeInfo> args;
args.resize(arity);
for (size_t i = 0; i < arity; ++i)
{
ObtainType<Args...>(i, args[i]);
}
cont_[str] = FunctionInfo(func_ptr, ret, args);
}
void CallFunc(const std::string& func_name,
std::vector<boost::variant<int, double>>& args_vec) {
auto it = cont_.find(func_name);
if (it != cont_.end())
{
// ???????
// And here I stucked
}
}
private:
std::map<std::string, FunctionInfo> cont_;
};
And then I stucked.
Don't know how to get function type information from my struct :).
Don't know how to convert vector of variants to arguments list.
Maybe my path was wrong? Can you suggest any solution of this problem except script engine like Lua?
You may do something like:
class BaseFunc {
public:
virtual ~BaseFunc() = default;
virtual void Call(std::vector<boost::variant<int, double>>& args_vec) const = 0;
};
template <typename F> class Function;
template <typename R, typename... Args> class Function<R(Args...)> : public BaseFunc
{
public:
Function(R (*f)(Args...)) : f(f) {}
void Call(std::vector<boost::variant<int, double>>& args_vec) const override
{
Call(args_vec, std::index_sequence_for<Args...>());
}
private:
template <std::size_t ... Is>
void Call(
std::vector<boost::variant<int, double>>& args_vec,
std::index_sequence<Is...>) const
{
// Add additional check here if you want.
f(boost::get<Args>(args_vec.at(Is))...);
}
private:
R (*f)(Args...);
};
Live example