class BaseClass{
public:
std::string name;
BaseClass(std::string typeName) : name(typeName) {};
std::string GetType(){ return name; }
};
template<typename T>
class DerivedClass : public BaseClass{
public:
T val;
DerivedClass(std::string typeName, T arg) : BaseClass(typeName), val(arg) {};
};
template<typename U, typename L>
void foo1(U & arg1, L & arg2)
{
std::cout << arg1.val + arg2.val << std::endl;
}
void foo(BaseClass *arg1, BaseClass *arg2)
{
if(arg1->GetType() == "Int")
{
auto p1 = (DerivedClass<int>*)arg1;
if(arg2->GetType() == "Int")
{
auto p2 = (DerivedClass<int>*)arg2;
foo1(*p1, *p2);
}
else if(arg2->GetType() == "Float")
{
auto p2 = (DerivedClass<float>*)arg2;
foo1(*p1, *p2);
}
//else if () AND SO ON ........
}
else if(arg1->GetType() == "Float")
{
auto p1 = (DerivedClass<float>*)arg1;
if(arg2->GetType() == "Int")
{
auto p2 = (DerivedClass<int>*)arg2;
foo1(*p1, *p2);
}
else if(arg2->GetType() == "Float")
{
auto p2 = (DerivedClass<float>*)arg2;
foo1(*p1, *p2);
}
}
//else if () AND SO ON .....
}
int main()
{
BaseClass *k1 = new DerivedClass<int>("Int", 2);
BaseClass *k2 = new DerivedClass<float>("Float", 4.32);
foo(k1, k2);
return 0;
}
我遇到了与上述测试案例类似的问题。 在函数foo中,有没有更优雅的方法解析多个类型到ifs的梯形图来运行模板函数? 如果对于1或2个参数没有那么糟糕的阶梯,那么(参数计数)^(类型计数);
答案 0 :(得分:1)
您可以使用一些模板魔法为您生成if
... else
链。首先,编写一个通用的编译时迭代函数:
template <typename TF, typename... Ts>
void for_each_arg(TF&& f, Ts&&... xs)
{
return (void)(int[]){(f(std::forward<Ts>(xs)), 0)...};
}
您还需要将类型绑定到字符串的内容:
template <typename T>
struct bound_type
{
using type = T;
std::string _name;
bound_type(std::string name) : _name{std::move(name)} { }
};
然后你可以用它来检查你感兴趣的类型:
void foo(BaseClass *arg1, BaseClass *arg2)
{
const auto for_bound_types = [](auto&& f)
{
return for_each_arg(std::forward<decltype(f)>(f),
bound_type<int>{"Int"},
bound_type<float>{"Float"},
bound_type<double>{"Double"});
};
for_bound_types([&](const auto& t1)
{
if(arg1->GetType() != t1._name) return;
for_bound_types([&](const auto& t2)
{
if(arg2->GetType() != t2._name) return;
using t1_type = typename std::decay_t<decltype(t1)>::type;
using t2_type = typename std::decay_t<decltype(t2)>::type;
auto& p1 = static_cast<DerivedClass<t1_type>&>(*arg1);
auto& p2 = static_cast<DerivedClass<t2_type>&>(*arg2);
foo1(p1, p2);
});
});
}
我想避免在这里使用std::string
,但编译时字符串在C ++中是不合理的。可以使用像typestring这样的东西。
在C ++ 17中,由于 fold表达式,for_each_arg
将是多余的。 std::apply
也可用于实施for_bound_types
。
const auto for_bound_types = [](auto&& f)
{
return std::apply([&](auto... xs){ (f(xs), ...); },
std::make_tuple(bound_type<int>{"Int"},
bound_type<float>{"Float"},
bound_type<double>{"Double"}));
};
答案 1 :(得分:1)
生成的代码为stripWhitespaceY
,但您可以让编译器为您完成。
获取args^types
或std::variant
,或自行撰写。
让每个参数为您提供带有副本的boost::variant
,或带有指向元素或其自身的指针的variant
。
对这些变体使用variant
或std::visit
。
boost::apply_visitor
现在我们得到:
template<typename T>
class DerivedClass;
class BaseClass{
public:
std::string name;
virtual std::variant< DerivedClass<int>*, DerivedClass<double>* >
self() = 0;
BaseClass(std::string typeName) : name(typeName) {};
std::string GetType(){ return name; }
};
template<typename T>
class DerivedClass : public BaseClass{
public:
T val;
DerivedClass(std::string typeName, T arg) : BaseClass(typeName), val(arg) {};
std::variant< DerivedClass<int>*, DerivedClass<double>* >
self() overload { return this; }
std::variant< DerivedClass<int> const*, DerivedClass<double> const* >
self() const overload { return this; }
};
现在这会将问题归结为&#34;如何撰写void foo(BaseClass *arg1, BaseClass *arg2)
{
auto a1 = arg1->self();
auto a2 = arg2->self();
auto foo_overloads = [](auto&&...args)->decltype(auto){ return foo(decltype(args)(args)...); };
std::visit( foo_overloads, a1, a2 );
}
和std::visit
&#34;。但两者的代码都可以在互联网上找到。两者都以std::variant
和std::experimental::variant
提供。
维护类型列表std::experimental::visit
int
可以在类型列表中完成,并从中生成列表double
。
如果您希望列表以运行时成本定制和动态,您可以改为使用类型列表,在使用点构建从variant<DerivedClass<int>*, DerivedClass<double>*>
到std::string
的地图(列出您的类型)支持那里,并在那里做同样的事情。