我有一个类似于这个的课程:
int add(int a,int b)
{
return a+b;
}
int sub(int a,int b)
{
return a-b;
}
class C
{
int m_functionType;
C(int functionType)
{
m_functionType=functionType;
}
int calc(int a, int b)
{
switch(m_functionType)
{
case 1: // add
return add(a,b);
break;
case 2: // subtract
return sub(a,b);
}
}
};
并使用如下:
main()
{
C add(1);
C sub(2);
auto x=add.calc(1,2);
auto z=sub.calc(2,1);
}
此代码有效,但应该调用的函数在运行时解析,我正在寻找一个解决方案来解决在编译时调用的函数。像这样的东西:
template <int func>
class C
{
int calc(int a, int b)
{
switch(func)
{
case 1: // add
return add(a,b);
break;
case 2: // subtract
return sub(a,b);
}
}
};
main()
{
C<1> add;
C<2> sub;
auto x=add.calc(1,2);
auto z=sub.calc(2,1);
}
以上代码是否在编译期间实际解析了该函数,或者它仍然在运行时解析它?
有什么方法可以使用模板类来做到这一点? 假设我想在Visual Studio 2013和GNU上编译它们,它们具有一些c ++ 11功能。
答案 0 :(得分:7)
在您的示例中func
在main
:
C add(1);
C sub(2);
编译时间意味着:
C<1> add;
C<2> sub;
如果上面的更改是可以接受的,那么C ++ 98/03经典的想法是使用函数重载:
template <int v>
struct IntToType {
enum {val = v};
};
int calc_impl(a, b, IntToType<1>) {
return add(a, b);
}
int calc_impl(a, b, IntToType<2>) {
return sub(a, b);
}
template <int func>
class C {
int calc(int a, int b) {
return calc_impl(a, b, IntToType<func>());
}
};
备注:强>
calc_impl
只是两个带三个参数的函数。省略第三个参数的名称,因为它未被使用。它们被第三个参数重载,因为IntToType<1>
和IntToType<2>
是两种不同的类型。calc_impl
个功能放入班级的私人部分,以便更好地符合人体工程学。答案 1 :(得分:0)
从外观上看,您确实希望将要作为模板参数调用的操作传递给外部函数,该函数间接调用。根据您的观点,可以将其视为策略类或策略模式 1 的实例。
由于模板主要基于类型,因此通常希望使用类而不是函数来执行此操作。除此之外,虽然有一些不同的可能方法,但它非常简单。
一种方法是让calc调用指定的策略以响应其自己的operator()
被调用。代码看起来像这样:
#include <iostream>
struct add {
int operator()(int a, int b) { return a + b; }
};
struct sub {
int operator()(int a, int b) { return a - b; }
};
template <class C>
struct calc {
int operator()(int a, int b) {
return C()(a, b);
}
};
使用它的代码可能如下所示:
int main() {
auto x=calc<add>()(1,2);
auto z=calc<sub>()(2,1);
}
另一种可能性是calc
在构造对象时执行计算,并根据需要返回结果。这避免了(除其他外)创建对象的额外一组parens,然后调用其operator()
进行计算。另一方面,它意味着从计算对象添加隐式转换运算符以返回计算结果,这是许多人不喜欢的。进入该路线的代码可能如下所示:
template<class C>
struct calc2 {
int val;
public:
calc2(int a, int b) : val(C()(a, b)) {}
operator int() { return val; }
};
// ...
std::cout << calc2<add>(1, 2) << "\n";
std::cout << calc2<sub>(2, 1) << "\n";
有点难以说明这两个选项之间哪个更合适(并且还有其他变体)。在这些之间,选择基本上是丑陋的调用和丑陋的隐式转换。
当然,取决于你在&#34;策略&#34;中所做的事情。部分事情,决定可能很简单 - 如果你真的需要只按需要执行动作,而不是立即创建(并且只保存结果直到需要),第二个根本不是一个选项
我应该补充一点,我假设您当前提供的整数用于确定要使用的操作是您所想出的实施的偶然副作用。换句话说,我假设更直接地指定操作本身就像我上面所做的那样真的更可取。
<子> 1.策略通常是一个完整的算法,而不是像添加和减去一样微不足道的事情,但我假设这只是一个例子,而你的真实应用程序做了一些更具实质性的事情。 子>
答案 2 :(得分:-1)
将在编译时解析将调用哪个函数,因为任何半正式的现代编译器都可以优化switch
中未使用的案例。