浅墨浓香

想要天亮进城,就得天黑赶路。

导航

6.3 Disable Templates with enable_if<>

6.3 使用enable_if<>来禁用模板

 

Since C++11, the C++ standard library provides a helper template std::enable_if<> to ignore function templates under certain compile-time conditions.

自从C++11开始,C++标准库提供了一个std::enable_if<>辅助模板,以便在某些编译条件下忽略函数模板。

For example, if a function template foo<>() is defined as follows:

例如,函数模板foo<>的定义如下:

template<typename T>
typename std::enable_if<(sizeof(T) > 4)>::type
foo() {
}

this definition of foo<>() is ignored if sizeof(T) > 4 yields false. if sizeof(T) > 4 yields true, the function template instance expands to

foo<>函数模板的定义在sizeof(T)>4不成立时被忽略掉。如果sizeof(T)>4,则函数模板的实例会展开成:

void foo() 
{ }

That is, std::enable_if<> is a type trait that evaluates a given compile-time expression passed as its (first) template argument and behaves as follows:

也就是说std::enable_if<>是一种类型萃取,它会将其(第1个)模板实参作为编译期表达式进行评估,其行为如下:

• If the expression yields true, its type member type yields a type:

如果表达式结果为true,它的type类型成员会返回一个类型:

– The type is void if no second template argument is passed.

      如果没有第2个模板参数,返回类型为void。

– Otherwise, the type is the second template argument type.

      否则,返回类型为其第2个模板参数的类型。

• If the expression yields false, the member type is not defined. Due to a template feature called SFINAE (substitution failure is not an error), which is introduced later (see Section 8.4 on page 129), this has the effect that the function template with the enable_if expression is ignored.

如果表达式结果为false,则其成员类型是未定义的。根据模板一个叫做SFINAE(替换失败不是错误)的规则,将导致包含std::enable_if表达式的函数模板被忽略掉。关于SFINAE将在后面的第129页8.4节介绍。

As for all type traits yielding a type since C++14, there is a corresponding alias template std::enable_if_t<>, which allows you to skip typename and ::type (see Section 2.8 on page 40 for details). Thus, since C++14 you can write

由于从C++14开始,所有的类型萃取(type traits)都会返回一个类型。可以使用一个与之对应的别名模板std::enable_if_t<>,这样就可以省略掉typename和::type(详见第40页的2.8节)。因此,从C++14开始,你可以编写

template<typename T>
std::enable_if_t<(sizeof(T) > 4)>
foo() {
}

If a second argument is passed to enable_if<> or enable_if_t<>:

假如给std::enable_if<>或std::enable_if_t<>传入第2个模板参数:

template<typename T>
std::enable_if_t<(sizeof(T) > 4), T>
foo() {
    return T();
}

the enable_if construct expands to this second argument if the expression yields true. So, if MyType is the concrete type passed or deduced as T, whose size is larger than 4, the effect is如果sizeof(T)>4表达式结果为true时,enable_if<>被会扩展成其第2个模板参数。因此,如果MyType是个具体类型或通过T推导的类型,且其size大于4时,那么等价于:

MyType foo();

 

Note that having the enable_if expression in the middle of a declaration is pretty clumsy. For this reason, the common way to use std::enable_if<> is to use an additional function template argument with a default value:

但是将enable_if表达式放在声明的中间是一个笨拙的做法。因此,使用std::enable_if<>更常见的做法是通常是使用一个额外、带有默认值的模板参数:

template<typename T,
         typename = std::enable_if_t<(sizeof(T) > 4)>>
void foo() {
}

which expands to

如果sizeof(T)>4时,它将会被展开为

template<typename T, typename = void>
void foo() {
}

if sizeof(T) > 4.

 

If that is still too clumsy, and you want to make the requirement/constraint more explicit, you can define your own name for it using an alias template:

如果这依然不够明智,并且希望需求或约束更加明显,你可以使用别名模板来自定义的一个名称。

template<typename T>
using EnableIfSizeGreater4 = std::enable_if_t<(sizeof(T) > 4)>;

template<typename T,
         typename = EnableIfSizeGreater4<T>>
void foo() {
}

See Section 20.3 on page 469 for a discussion of how std::enable_if is implemented.

关于std::enable_if实现的更多讨论,请参阅第469页的20.3节。