我有两个枚举,基本上(在运行时)确定要做什么。 'mapping'看起来像
GetNameService
问题是,fragmentB
,struct Foo { class CA; class CB; class CC; CA a; CB b; CC c; };
enum Base { A, B, C };
enum Func { X, Y };
Foo foo;
// A, X => use(foo.a.x());
// A, Y => use(foo.a.y());
// B, X => use(foo.b.x());
// B, Y => use(foo.b.y());
和a
以及b
和C
的返回类型都是不同的类型(一些非常庞大的模板类型。)
使用开关或ifs映射两个枚举非常难看,需要付出很多努力,所以我想知道,如果我能以某种方式写出这样的东西:
x()
编辑1:
我无法编辑课程y()
,struct Foo { class CA; class CB; class CC; CA a; CB b; CC c; };
enum Base { A, B, C, };
enum Func { X, Y, };
template <typename T> auto applyFunc(Func f, T t)
{
switch(f)
{
case X: return t.x();
case Y: return t.y();
}
}
auto getBase(Base b, Foo f)
{
switch(b)
{
case A: return f.a;
case B: return f.b;
case C: return f.c;
}
}
Func f;
Base b;
Foo foo;
use(applyFunc(f, getBase(b, foo)));
和CA
。我也无法编辑CB
和CC
的类/返回类型。所有这些类型都来自外部图书馆。
答案 0 :(得分:4)
您可以使用延续传递方式。
template <class F> void applyFunc(WhichFunc w, T t, F f)
{
switch(w)
{
case X: f(t.x());
case Y: f(t.y());
}
}
template<class F>
void getBase(Base b, Foo foo, F f)
{
switch(b)
{
case A: f(foo.a);
case B: f(foo.b);
case C: f(foo.c);
}
}
而不是返回,您将下一步作为参数传递给前一步。
Func f;
Base b;
Foo foo;
getBase(b, [&](auto&&b){ applyFunc( f, b, [&](auto&& r){ use(r); } ); } );
或某些(可能存在拼写错误)。
std::variant
(或者boost)可用于将延续移动到返回值之后。
auto b = getBase(b);
auto r = visit( b, [&](auto&& b){ return applyFunc( f, b ); } );
visit( r, [](auto&& r){ use(r); } );
而不是继续,上面的每一个都返回variant<possible_return_types_go_here>
。
答案 1 :(得分:1)
简而言之:你做不到。函数的返回类型必须是众所周知的编译时间。实际上,尝试在具有auto
返回类型的函数内返回不同类型,即使您使用模板,它也会给您编译错误。
您的解决方案可能包含多头的使用。
答案 2 :(得分:1)
另一种解决方案是使用特征:
struct Foo { class CA {}; class CB {}; class CC {}; CA a; CB b; CC c; };
enum Base { A, B, C, };
enum Func { X, Y, };
template<Base> struct GetBaseTraits;
template<> struct GetBaseTraits<Base::A> { using type = Foo::CA; };
template<> struct GetBaseTraits<Base::B> { using type = Foo::CB; };
template<> struct GetBaseTraits<Base::C> { using type = Foo::CC; };
template<Base b>
typename GetBaseTraits<b>::type getBase(Foo f);
template<> typename GetBaseTraits<A>::type getBase<A>(Foo f) { return f.a; }
template<> typename GetBaseTraits<B>::type getBase<B>(Foo f) { return f.b; }
template<> typename GetBaseTraits<C>::type getBase<C>(Foo f) { return f.c; }
int main() {
Foo f{};
Foo::CA ca = getBase<A>(f);
Foo::CB cb = getBase<B>(f);
Foo::CC cc = getBase<C>(f);
}
答案 3 :(得分:0)
函数应始终返回具有相同数据类型的值(在编译时确定)。你可以做的是使用某种形式的变体,例如boost::variant,或者创建你自己的变体类型:
enum ReturnType {
RET_STR, RET_INT, RET_DBL
};
struct variant {
ReturnType valtype;
string str;
int i;
double d;
};
string f1() { ... }
int f2() { ... }
double f3() { ... }
variant f(int x) {
variant v;
switch (x) {
case 0:
v.valtype = RET_STR;
v.str = f1();
break;
case 1:
v.valtype = RET_INT;
v.str = f2();
break;
case 2:
v.valtype = RET_DBL;
v.str = f3();
break;
}
return v;
}
或者,您可以使用某种形式的多态:
class result_handler {
public:
virtual ~result_handler(){}
virtual void handle_string(string s) = 0;
virtual void handle_int(int i) = 0;
virtual void handle_double(double d) = 0;
};
void f(int x, result_handler* h) {
switch (x) {
case 0:
h->handle_string(f1());
break;
case 1:
h->handle_int(f2());
break;
case 2:
h->handle_double(f3());
break;
}
}
class my_result_handler : public result_handler {
public:
virtual void handle_string(string s) { cout << "string " << s << endl; }
virtual void handle_int(int i) { cout << "int " << i << endl; }
virtual void handle_double(double d) { cout << "double " << d << endl; }
};
答案 4 :(得分:0)
如果在编译时已知参数,则可以使用标签分派:
template <Base> BaseTag{};
decltype(auto) getBaseImpl(Foo& foo, BaseTag<Base::A>) { return foo.a; }
decltype(auto) getBaseImpl(Foo& foo, BaseTag<Base::B>) { return foo.b; }
decltype(auto) getBaseImpl(Foo& foo, BaseTag<Base::C>) { return foo.c; }
template <Base base>
decltype(auto) getBase(Foo& foo) { return getBaseImpl(foo, BaseTag<base>{}); }
template <Func> FuncTag{};
template <typename T>
decltype(auto) getFuncImpl(T& t, FuncTag<Func::X>) { return t.x(); }
template <typename T>
decltype(auto) getFuncImpl(T& t, FuncTag<Func::Y>) { return t.y(); }
template <typename T, Func func>
decltype(auto) getFunc(T& t) { return getFuncImpl(f, FuncTag<func>{}); }
最后:
template <Base base, Func func>
decltype(auto) getElem(Foo& foo) { return getFunc<func>(getBase<base>(foo)); }