gpt4 book ai didi

c++ - 从一组有限的类静态转换为一个类

转载 作者:塔克拉玛干 更新时间:2023-11-03 00:27:40 26 4
gpt4 key购买 nike

我想对集合中的其中一个类实现静态转换,作为可变模板参数传递:

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

好吧,我希望代码不言自明。入门代码:https://godbolt.org/z/WfaFt-我正在寻找 apply_casted 的实现。如何迭代 Candidates...在编译时可能是最困难的部分。

最佳答案

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


如果返回类型可以不同,则应指定一个通用类型作为 apply_casted 的结果:

std::common_type_t<std::invoke_result_t<Fn, Candidate&>
, std::invoke_result_t<Fn, Candidates&>...>

可以使用 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


为了获得更好的性能,您应该使用类似于下面的跳转表:

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

关于c++ - 从一组有限的类静态转换为一个类,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53618358/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com