c ++ enable_if用于非类型模板参数

Ser*_*mal 7 c++ templates template-specialization enable-if non-type

我对部分模板特化有点困惑...我有一些代码依赖于算术数据类型T,并且在一个小的整数DIM上.我希望能够为不同的DIM值指定不同的类方法.使用部分模板专业化的不可能性使我探索了enable_if.这正是我所需要的...除了我希望它返回一个数字而不是一个类型.我怎样才能做到这一点?以下代码应说明我想要的内容.

#include <stdio.h>
#include <iostream>
#include <type_traits>

template <typename T, int DIM>
class foo{
    public:
        T function();

};


template <typename T, int DIM>
T foo<T, std::enable_if<DIM == 1>::value>::function(){
    // do something
    return 1.0;
}

template <typename T, int DIM>
T foo<T, std::enable_if<DIM == 2>::value>::function(){  
    // do something else
    return 2342.0;
}

int main(){
    foo<int, 1> object;
    int ak = object.function();
    std::cout << ak << "\n";

    return 0;   
}
Run Code Online (Sandbox Code Playgroud)

Ale*_*agh 8

你完全可以做你想做的事情enable_if,记住,当条件为假时,替换必须失败,所以你必须调用type以确保在专门针对各种条件时替换失败.

#include <stdio.h>
#include <iostream>
#include <type_traits>

template <typename T, int DIM>
class foo
{
public:
    template <int D = DIM>
    typename std::enable_if<D == 1, T>::type
    function()
    {
        // do something
        return 1.0;
    }

    template <int D = DIM>
    typename std::enable_if<D == 2, T>::type
    function()
    {
        // do something else
        return 2342.0;
    }

};

int main(){
    foo<int, 1> object;
    int ak = object.function();
    std::cout << ak << "\n";

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

对于简单的场景,例如上面的场景(您检查特定值而不是一系列值),您也可以使用局部特化.但是,如果你想专门研究所有的价值1-50,那么另一个51-200,然后是一个通用的秋天,enable_if效果很好.

您还可以enable_if在模板签名中使用.只是一个简单的例子.

#include <stdio.h>
#include <iostream>
#include <type_traits>

template <typename T, int DIM>
class foo
{
public:
    template <int D = DIM, typename std::enable_if<D == 1, void>::type* = nullptr>
    T function()
    {
        // do something
        return 1.0;
    }

    template <int D = DIM, typename std::enable_if<D == 2, void>::type* = nullptr>
    T function()
    {
        // do something else
        return 2342.0;
    }

};

int main(){
    foo<int, 1> object;
    int ak = object.function();
    std::cout << ak << "\n";

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

  • 很好,但我认为可以使它更简单:没有必要镜像每个模板参数(`U`和`D`)来激活SFINAE:它足够参与`std :: enable_if`测试中的模板参数.所以应该简单地作为`template <int D = DIM,typename std :: enable_if <D == 1> :: type*= nullptr> T function()`(和`void`是`std的默认返回类型: :enable_if` (2认同)
  • 或者`template <int D = DIM> typename std :: enable_if <D == 1,T> :: type function()` (2认同)

Jar*_*d42 5

您可以部分特化整个类:

template <typename T, int DIM>
class foo;

template <typename T>
class foo<T, 1>
{
public:
    T function() {
         // do something
         return 1.0;
     }
};

template <typename T>
class foo<T, 2>
{
public:
    T function() {
         // do something
         return 2342.0;
     }
};
Run Code Online (Sandbox Code Playgroud)

如果两个专业化之间有很多公共代码,您仍然可以使用继承(从公共部分继承或仅从专业部分继承)。

一种简单的替代方法是使用标签调度:

template <typename T, int dim>
class foo
{
public:
    T function();
};

 template <typename T>
 T function_helper(foo<T, 1>&) {
     // do something
     return 1.0;
 }

 template <typename T>
 T function_helper(foo<T, 2>&) {
     // do something
     return 2342.0;
 }

template <typename T, int dim>
T foo::function() {
    return function_helper(*this);
}
Run Code Online (Sandbox Code Playgroud)

但在 C++17 中,if constexpr允许更简单的语法:

template <typename T, int DIM>
class foo
{
public:
    T function() {
        if constexpr (DIM == 1) {
            // do something
            return 1.0;
        } else if constexpr (DIM == 2) {
            // do something
            return 2342.0;
        }
    } 
};
Run Code Online (Sandbox Code Playgroud)

带有约束的 C++20 允许

template <typename T, int DIM>
class foo
{
public:
    T function() requires (DIM == 1) {
        // do something
        return 1.0;
    }
    T function() requires (DIM == 2) {
        // do something
        return 2342.0;
    } 
};
Run Code Online (Sandbox Code Playgroud)