我记得读过一些文章,使用新的 C++ 特性在编译器时实现选择,但不知道如何去做。例如,我有一个方法执行以下操作
template<class T>
void foo()
{
if (std::is_abstract<T>::value)
do something;
else
do others.
}
编译时决策通常通过重载选择来完成。
void foo_impl(std::true_type) {
do something;
}
void foo_impl(std::false_type) {
do others.
}
template<class T>
void foo()
{
foo_impl(std::is_abstract<T>());
}
如果你的两个分支都编译,上面的代码实际上是可以的,并且会在编译时进行选择:编译器会检测到一个分支是死的并且永远不会使用。优化时没有自尊的编译器会使用分支。
特别是当分支可能无法根据类型编译时,您可以使用std::enable_if
有条件地使重载可用:
template <typename T>
typename std::enable_if<std::is_abstract<T>::value>::type foo()
{
do something
}
template <typename T>
typename std::enable_if<!std::is_abstract<T>::value>::type foo()
{
do other
}
该std::is_abstract
实用程序是类型 trait的示例,我喜欢遵循经典的选择器习惯用法:
#include<iostream>
#include<type_traits>
template<bool>
struct algorithm_selector {
static void implementation() {
std::cout<<"I am using the default implementation"<<std::endl;
}
};
template<>
struct algorithm_selector<true> {
static void implementation() {
std::cout<<"I am using the 'custom' implementation"<<std::endl;
}
};
template<typename T>
void foo() {
algorithm_selector<std::is_abstract<T>::value>::implementation();
}
struct ABC { virtual void bar() const = 0; };
struct Derived : ABC { };
struct Blah {};
int main() {
foo<ABC>();
foo<Derived>();
foo<Blah>();
return 0;
}
编译为 (gcc 4.8.1)g++ example.cpp -std=c++11
产生输出:
I am using the 'custom' implementation
I am using the 'custom' implementation
I am using the default implementation
我喜欢它的地方在于它超越了 *enable_if* 基本原理(至少在概念上):它为我提供了可用于在编译时选择任意策略的习语。这可能只是一个偏好问题,但对我来说,这个成语是坚如磐石的。另外,请查看Andrei Alexandrescu 书中描述的策略模式;它们与由编译时功能提供支持的设计灵活性有关。