4

我记得读过一些文章,使用新的 C++ 特性在编译器时实现选择,但不知道如何去做。例如,我有一个方法执行以下操作

template<class T>
void foo()
{
   if (std::is_abstract<T>::value)
         do something;
   else
         do others.
}
4

3 回答 3

7

编译时决策通常通过重载选择来完成。

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>());
}
于 2013-09-15T03:24:38.690 回答
6

如果你的两个分支都编译,上面的代码实际上是可以的,并且会在编译时进行选择:编译器会检测到一个分支是死的并且永远不会使用。优化时没有自尊的编译器会使用分支。

特别是当分支可能无法根据类型编译时,您可以使用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
}
于 2013-09-15T03:26:24.490 回答
1

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 书中描述的策略模式;它们与由编译时功能提供支持的设计灵活性有关。

于 2013-09-15T05:15:41.467 回答