根据运行时参数避免模板实例化的代码重复
Avoiding code duplication for template instantiations depending on runtime parameters
我正在使用其他人编写的C++库,该库(不幸的是imo)实现了封装在类中的几种算法,这些算法的行为可以通过作为模板参数传递的参数进行微调(参数通常也是类)。例如,可能会有一个这样的类模板:
template<typename Param1, typename Param2, typename Param3>
class Foo {
// ...
};
我想使用此库编写一个程序,该程序需要根据运行时信息创建Foo
实例。我的问题是,假设有N1
、N2
和N3
的有效类型可以传递给Param1
、Param2
和Param3
,当我想实例化Foo
的不同特定化时,我可能需要在我的代码中的某个时候创建多达N1 x N2 x N3
个分支。例如,假设我在运行时通过用户输入获得三个字符串,每个字符串都决定了Foo
的模板参数之一应该是哪种类型,那么我需要做这样的事情:
std::string s1, s2, s3;
// instantiate s1, s2, s3 from user input
if (s1 == "Param1_1" && s2 == "Param2_1" && s3 == "Param3_1") {
Foo<Param1_1, Param2_1, Param3_1> foo;
} else if (s1 == "Param1_1" && s2 == "Param2_1" && s3 == "Param3_2") {
Foo<Param1_1, Param2_1, Param3_2> foo;
}
// ...
其中Param1_1
是Param1
等的有效类型。如何更优雅地实现这一点?(理想情况下仅使用 C++11 或最多使用 C++17 个功能)。
您可以对每种类型使用std::variant
(c++17),并对调度使用std::visit
:
template <typename T> struct Tag{ using type = T;};
std::variant<Tag<T1>, Tag<T2>, Tag<T3>/*..*/> getType(const std::string& s)
{
if (s == "Param1") { return Tag<T1>{}; }
else if (s == "Param2") { return Tag<T2>{}; }
// ...
}
void bar(const std::string& s1, const std::string& s2, const std::string& s3)
{
auto v1 = getType(s1);
auto v2 = getType(s2);
auto v3 = getType(s3);
std::visit([](auto t1, auto t2, auto t3)
{
Foo<typename decltype(t1)::type,
typename decltype(t2)::type,
typename decltype(t3)::type> foo;
/*..*/
}, v1, v2, v3);
}
从 C++11 开始,您可以创建一系列函数(每种类型一个函数)来选择和传输正确的模板参数;调用的最后一个函数(以下示例中的第一个函数)可以创建Foo
对象。
不是很优雅,但你可以避免N1 x N2 x N3
乘法效应。
template <typename ... PrevParams>
void for_s3 (std::string const & s3)
{
if ( "Param3_1" == s3 )
Foo<PrevParams..., Param3_1>{}
else if ( "Param3_2" == s3 )
Foo<PrevParams..., Param3_2>{};
// other cases
}
template <typename ... PrevParams>
void for_s2 (std::string const & s2, std::string const & s3)
{
if ( "Param2_1" == s2 )
for_s3<PrevParams..., Param2_1>(s3);
else if ( "Param2_2" == s2 )
for_s3<PrevParams..., Param2_2>(s3);
// other cases
}
void for_s1 (std::string const & s1, std::string const & s2, std::string const & s3)
{
if ( "Param1_1" == s1 )
for_s2<Param1_1>(s2, s3);
else if ( "Param1_2" == s1 )
for_s2<Param1_2>(s2, s3);
// other cases
}
也许更优雅和灵活一点(您可以轻松添加其他字符串和参数),但运行时成本更高,双功能解决方案
template <typename ... Params>
void select_foo ()
{
Foo<Params...> f;
// do something with f
}
template <typename ... PrevParams, typename ... Ts>
void select_foo (std::string const & s, Ts const & ... ts)
{
if ( "Param1_1" == s )
select_foo<PrevParams..., Param1_1>(ts...);
else ( "Param1_2" == s )
select_foo<PrevParams..., Param1_2>(ts...);
// other Param1_x cases
else if ( "Param2_1" == s )
select_foo<PrevParams..., Param2_1>(ts...);
else ( "Param2_2" == s )
select_foo<PrevParams..., Param2_2>(ts...);
// other Param2_x cases
else if ( "Param3_1" == s )
select_foo<PrevParams..., Param3_1>(ts...);
else ( "Param3_1" == s )
select_foo<PrevParams..., Param3_2>(ts...);
// other Param3_x cases
}
相关文章:
- 为什么我们不在下面给出的代码中使用指针来实例化C++的实体对象?
- 以下代码如何工作以每次为唯一调用堆栈唯一实例化模板函数?
- 在C++代码中搜索对象的实例化位置
- 生成代码(在编译时)以调用模板的每个实例化的静态函数
- 根据运行时参数避免模板实例化的代码重复
- 如何在代码中创建抽象类,让蓝图扩展它,并将该蓝图返回给代码进行实例化?
- 如何在代码中实例化 Vst3 插件?对于 vst3 主机应用
- 生成代码实例化具有不同参数的函数模板
- 如何使用 C++11 unique_ptr实例化我的代码
- 在CNI/C++代码中实例化一个模板类
- 获取在C++中实例化的TCL解释器中执行代码的行号
- 我可以使用decltype()来避免显式模板实例化中的代码重复吗
- 如何在函数调用的一行代码中实例化类
- typedef和显式实例化之间的代码重复
- 用于实例化模板化代码的显式习惯用法 - 不包括其源代码
- 为什么下面的代码会导致模板实例化
- 强制 clang 为类模板实例化的从不引用的静态成员函数发出代码
- C++模板中条件代码实例化的最干净方法
- C++模板函数实例化代码大小
- 编译器:类实例化代码是如何编译的