c++ - Dispatch a template function by dynamically known type - Stack Overflow

Think of a type P that should be thought of as templated by some type T. However, P wraps some perl lib

Think of a type P that should be thought of as templated by some type T. However, P wraps some perl library, and the type T is only known at run time. On the C++ side, I can ask a P for its type. There are only finitely many choices. I have a function f that should be templated by T. Because of this perl-library thing, I have to dispatch on f's template dynamically. Because I have several functions like f, I want to solve this as generically as possible. At the moment, I have

template<typename Fun, typename... Args>
P dispatch(Fun fun, P p, Args&&... args){
    if(p.hasmembertype("T1"))
        return fun.template operator()<T1>(p, std::forward<Args>(args)...);
    if(p.hasmembertype("T2"))
        return fun.template operator()<T2>(p, std::forward<Args>(args)...);
    ...
    else
        throw std::runtime_error("Unsupported type.");
}

This leaves me with the problem that every time I want to use this, I have to wrap a concrete f in a functor:

struct {
    template<typename T>
    P operator()(P& p) {
        return f<T>(p);
    }
} static const f_wrapper;
...
dispatch(f_wrapper, p, ...);

Can this be solved more elegantly? I am bound to C++17; however, I'd be also interested if there exists an elegant solition in a more recent C++ standard.

Edit: To clarify, it is not the case that P is a T1, T2 etc., but P has some member type T that I can ask for with hasmembertype.

Think of a type P that should be thought of as templated by some type T. However, P wraps some perl library, and the type T is only known at run time. On the C++ side, I can ask a P for its type. There are only finitely many choices. I have a function f that should be templated by T. Because of this perl-library thing, I have to dispatch on f's template dynamically. Because I have several functions like f, I want to solve this as generically as possible. At the moment, I have

template<typename Fun, typename... Args>
P dispatch(Fun fun, P p, Args&&... args){
    if(p.hasmembertype("T1"))
        return fun.template operator()<T1>(p, std::forward<Args>(args)...);
    if(p.hasmembertype("T2"))
        return fun.template operator()<T2>(p, std::forward<Args>(args)...);
    ...
    else
        throw std::runtime_error("Unsupported type.");
}

This leaves me with the problem that every time I want to use this, I have to wrap a concrete f in a functor:

struct {
    template<typename T>
    P operator()(P& p) {
        return f<T>(p);
    }
} static const f_wrapper;
...
dispatch(f_wrapper, p, ...);

Can this be solved more elegantly? I am bound to C++17; however, I'd be also interested if there exists an elegant solition in a more recent C++ standard.

Edit: To clarify, it is not the case that P is a T1, T2 etc., but P has some member type T that I can ask for with hasmembertype.

Share Improve this question edited Mar 25 at 9:56 Bubaya asked Mar 25 at 9:10 BubayaBubaya 8417 silver badges19 bronze badges 6
  • You probably want to rewrite this with a std::variant<T1, T2, T3>. We do not need to know that this variant originated in Perl - the answer would be the same if that variant came from Python. What is important is that set T1,T2,T3. It has to be finite and enumerable. A runtime error is literally impossible then. (Of course, you could have a runtime error reading data from perl.) – MSalters Commented Mar 25 at 9:14
  • @MSalters Good point. I think it's not applicable because T is a member type of some Perl structure; see my edit, please. – Bubaya Commented Mar 25 at 9:16
  • I think it's still applicable. You want a single conversion of P to std::variant<T1,T2,T3> so that you can then call std::visit([](auto&& p) { polarize(p); }, myVar ); – MSalters Commented Mar 25 at 9:23
  • @MSalters No: p has some member that's hidden from me. I can ask for the type of that member by string, but I cannot access it in the sense of a C++ member. The type of p is P in all cases, and f is templated not on the type of p, but on the type of something inside p. If I misunderstand you, I am deeply sorry. Please post an answer or elaborate in that case. – Bubaya Commented Mar 25 at 9:30
  • If you cannot retrieve "members" T1/T2 directly, it seems you are limited to use the function from the library (polarize<T>), whereas you cannot have my_func<T>. – Jarod42 Commented Mar 25 at 10:02
 |  Show 1 more comment

2 Answers 2

Reset to default 3

The solution here is to define a single non-template function with signature std::variant<T1, T2, T3> get_member(P const&).

You can then call std::visit( [](auto&& p){polarize(p);}, get_member(p) );

The get_member code will need the logic to extract the Perl member data, using that p.hasmembertype("T1") logic from the question.

Rather than wrap every function, you can wrap P once.

template <typename T>
struct WrappedP {
    P value;
    using type = T;
};

template <typename... Ts>
struct VariantP {
    VariantP(P) { /* existing dispatch to populate variant */ }
    std::variant<WrappedP<Ts>...> variant;
};

Then for each template, you can

std::visit([]<typename T>(WrappedP<T>& wrapper){ f<T>(wrapper.value); }, variant);

发布者:admin,转转请注明出处:http://www.yc00.com/questions/1744207598a4563178.html

相关推荐

发表回复

评论列表(0条)

  • 暂无评论

联系我们

400-800-8888

在线咨询: QQ交谈

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信