C++ 部分模板专业化:成员函数
C++ Partial Template Specialization: Member Functions
我有模板
template <int a, int b>
class MyTemplateClass
{
// ....
void computeSomething();
};
我想部分专注于 b 的两个特殊情况:
template<int a>
void MyTemplateClass<a, 2> :: computeSomething()
{
// Special case for b=2 here
}
template<int a>
void MyTemplateClass<a, 3> :: computeSomething()
{
// Special case for b=3 here
}
但是,据我所知,偏特化对于成员函数是无效的。我怎样才能实现我想要的?还有其他解决办法吗?谢谢!
因为模板的类型名是已知的,你可以在computeSomething
函数中添加一些实现,来分支流程,像这样:
template <int a, int b>
class MyTemplateClass
{
// ....
void computeSomething()
{
if (b == 2) { computeWith2(); }
else if (b == 3) { computeWith3(); }
else { computerNormally(); }
};
}
一种方法是将此 class 的计算提取到一个单独的计算中。
然后你可以只特化那个计算 class:
template <int a, int b>
class MyTemplateClass
{
// ....
void computeSomething() {
Computation<a, b> c;
c.compute();
}
};
template <int a, int b>
struct Computation { void compute () {} };
template <int a>
struct Computation<a, 2> { void compute () {} };
template <int a>
struct Computation<a, 3> { void compute () {} };
虽然 IMO 最好不要使用专业化,而是使用不同的(描述性!)名称和编译时间条件以在它们之间进行选择:
template<bool Condition,
typename Then,
typename Else>
using if_t = typename std:: conditional<
Condition, Then, Else>:: type;
template <int a, int b>
class MyTemplateClass
{
// ....
using Computation =
if_t<b == 2,
B2Comp<a>,
if_t<b == 3,
B3Comp<a>,
DefaultComp<a, b> > >;
void computeSomething() {
Computation c;
c.compute();
}
};
// Add (template) classes, B3Comp and DefaultComp
如果你已经可以尝试C++17,那么上面可以重写为:
template <int a, int b>
class MyTemplateClass
{
// ....
void computeSomething() {
if constexpr (b == 2) {
B2Comp<a> comp;
comp.compute();
} else if constexpr (b == 3) {
B3Comp<a> comp;
comp.compute();
} else {
DefaultComp<a, b> comp;
comp.compute();
// Or just put the code here, if it's short
}
}
};
您还可以使用模板函数来代替模板 classes。
与使用普通 if 相比,这避免了对 "unneeded" 代码路径的评估,因此可以在那里放置格式错误的代码(如同一模板的递归实例化)。
一个可能的方法是 estract compute()
,只为它创建一个基础 class 并专门化这个基础 class.
我的意思是...如果您为 fooSub
创建一个通用版本和两个专业化版本
template <int a, int b>
struct fooSub
{
void compute ()
{ std::cout << "- foo generic compute()" << std::endl; }
};
template <int a>
struct fooSub<a, 2>
{
void compute ()
{ std::cout << "- foo compute() for 2" << std::endl; }
};
template <int a>
struct fooSub<a, 3>
{
void compute ()
{ std::cout << "- foo compute() for 3" << std::endl; }
};
您可以 "specialize" 通过继承在 foo
中进行计算,如下所示
template <int a, int b>
struct foo : public fooSub<a, b>
{ };
如果您至少可以使用 C++11,另一种可能的解决方案是 activate/deactivate 使用 SFINAE (std::enable_if
) 的 compute()
不同版本,如下所示 bar
class
template <int a, int b>
struct bar
{
template <int bb = b>
typename std::enable_if<(b == bb) && (b != 2) && (b != 3)>::type
compute ()
{ std::cout << "- bar generic compute()" << std::endl; }
template <int bb = b>
typename std::enable_if<(b == bb) && (b == 2)>::type compute ()
{ std::cout << "- bar compute() for 2" << std::endl; }
template <int bb = b>
typename std::enable_if<(b == bb) && (b == 3)>::type compute ()
{ std::cout << "- bar compute() for 3" << std::endl; }
};
两种方式都遵循完整的可编译示例
#include <iostream>
#include <type_traits>
template <int a, int b>
struct fooSub
{
void compute ()
{ std::cout << "- foo generic compute()" << std::endl; }
};
template <int a>
struct fooSub<a, 2>
{
void compute ()
{ std::cout << "- foo compute() for 2" << std::endl; }
};
template <int a>
struct fooSub<a, 3>
{
void compute ()
{ std::cout << "- foo compute() for 3" << std::endl; }
};
template <int a, int b>
struct foo : public fooSub<a, b>
{ };
template <int a, int b>
struct bar
{
template <int bb = b>
typename std::enable_if<(b == bb) && (b != 2) && (b != 3)>::type
compute ()
{ std::cout << "- bar generic compute()" << std::endl; }
template <int bb = b>
typename std::enable_if<(b == bb) && (b == 2)>::type compute ()
{ std::cout << "- bar compute() for 2" << std::endl; }
template <int bb = b>
typename std::enable_if<(b == bb) && (b == 3)>::type compute ()
{ std::cout << "- bar compute() for 3" << std::endl; }
};
int main()
{
foo<0, 1>{}.compute(); // print - foo generic compute()
foo<1, 2>{}.compute(); // print - foo compute() for 2
foo<2, 3>{}.compute(); // print - foo compute() for 3
bar<2, 1>{}.compute(); // print - bar generic compute()
bar<3, 2>{}.compute(); // print - bar compute() for 2
bar<4, 3>{}.compute(); // print - bar compute() for 3
}
我有模板
template <int a, int b>
class MyTemplateClass
{
// ....
void computeSomething();
};
我想部分专注于 b 的两个特殊情况:
template<int a>
void MyTemplateClass<a, 2> :: computeSomething()
{
// Special case for b=2 here
}
template<int a>
void MyTemplateClass<a, 3> :: computeSomething()
{
// Special case for b=3 here
}
但是,据我所知,偏特化对于成员函数是无效的。我怎样才能实现我想要的?还有其他解决办法吗?谢谢!
因为模板的类型名是已知的,你可以在computeSomething
函数中添加一些实现,来分支流程,像这样:
template <int a, int b>
class MyTemplateClass
{
// ....
void computeSomething()
{
if (b == 2) { computeWith2(); }
else if (b == 3) { computeWith3(); }
else { computerNormally(); }
};
}
一种方法是将此 class 的计算提取到一个单独的计算中。
然后你可以只特化那个计算 class:
template <int a, int b>
class MyTemplateClass
{
// ....
void computeSomething() {
Computation<a, b> c;
c.compute();
}
};
template <int a, int b>
struct Computation { void compute () {} };
template <int a>
struct Computation<a, 2> { void compute () {} };
template <int a>
struct Computation<a, 3> { void compute () {} };
虽然 IMO 最好不要使用专业化,而是使用不同的(描述性!)名称和编译时间条件以在它们之间进行选择:
template<bool Condition,
typename Then,
typename Else>
using if_t = typename std:: conditional<
Condition, Then, Else>:: type;
template <int a, int b>
class MyTemplateClass
{
// ....
using Computation =
if_t<b == 2,
B2Comp<a>,
if_t<b == 3,
B3Comp<a>,
DefaultComp<a, b> > >;
void computeSomething() {
Computation c;
c.compute();
}
};
// Add (template) classes, B3Comp and DefaultComp
如果你已经可以尝试C++17,那么上面可以重写为:
template <int a, int b>
class MyTemplateClass
{
// ....
void computeSomething() {
if constexpr (b == 2) {
B2Comp<a> comp;
comp.compute();
} else if constexpr (b == 3) {
B3Comp<a> comp;
comp.compute();
} else {
DefaultComp<a, b> comp;
comp.compute();
// Or just put the code here, if it's short
}
}
};
您还可以使用模板函数来代替模板 classes。
与使用普通 if 相比,这避免了对 "unneeded" 代码路径的评估,因此可以在那里放置格式错误的代码(如同一模板的递归实例化)。
一个可能的方法是 estract compute()
,只为它创建一个基础 class 并专门化这个基础 class.
我的意思是...如果您为 fooSub
template <int a, int b>
struct fooSub
{
void compute ()
{ std::cout << "- foo generic compute()" << std::endl; }
};
template <int a>
struct fooSub<a, 2>
{
void compute ()
{ std::cout << "- foo compute() for 2" << std::endl; }
};
template <int a>
struct fooSub<a, 3>
{
void compute ()
{ std::cout << "- foo compute() for 3" << std::endl; }
};
您可以 "specialize" 通过继承在 foo
中进行计算,如下所示
template <int a, int b>
struct foo : public fooSub<a, b>
{ };
如果您至少可以使用 C++11,另一种可能的解决方案是 activate/deactivate 使用 SFINAE (std::enable_if
) 的 compute()
不同版本,如下所示 bar
class
template <int a, int b>
struct bar
{
template <int bb = b>
typename std::enable_if<(b == bb) && (b != 2) && (b != 3)>::type
compute ()
{ std::cout << "- bar generic compute()" << std::endl; }
template <int bb = b>
typename std::enable_if<(b == bb) && (b == 2)>::type compute ()
{ std::cout << "- bar compute() for 2" << std::endl; }
template <int bb = b>
typename std::enable_if<(b == bb) && (b == 3)>::type compute ()
{ std::cout << "- bar compute() for 3" << std::endl; }
};
两种方式都遵循完整的可编译示例
#include <iostream>
#include <type_traits>
template <int a, int b>
struct fooSub
{
void compute ()
{ std::cout << "- foo generic compute()" << std::endl; }
};
template <int a>
struct fooSub<a, 2>
{
void compute ()
{ std::cout << "- foo compute() for 2" << std::endl; }
};
template <int a>
struct fooSub<a, 3>
{
void compute ()
{ std::cout << "- foo compute() for 3" << std::endl; }
};
template <int a, int b>
struct foo : public fooSub<a, b>
{ };
template <int a, int b>
struct bar
{
template <int bb = b>
typename std::enable_if<(b == bb) && (b != 2) && (b != 3)>::type
compute ()
{ std::cout << "- bar generic compute()" << std::endl; }
template <int bb = b>
typename std::enable_if<(b == bb) && (b == 2)>::type compute ()
{ std::cout << "- bar compute() for 2" << std::endl; }
template <int bb = b>
typename std::enable_if<(b == bb) && (b == 3)>::type compute ()
{ std::cout << "- bar compute() for 3" << std::endl; }
};
int main()
{
foo<0, 1>{}.compute(); // print - foo generic compute()
foo<1, 2>{}.compute(); // print - foo compute() for 2
foo<2, 3>{}.compute(); // print - foo compute() for 3
bar<2, 1>{}.compute(); // print - bar generic compute()
bar<3, 2>{}.compute(); // print - bar compute() for 2
bar<4, 3>{}.compute(); // print - bar compute() for 3
}