专门针对大模板类中的单一方法

Cyg*_*sX1 17 c++ templates c++11

在C++中,如果要部分地专门化模板类中的单个方法,则必须专门化整个类(例如,在模板专门化中使用带有多个模板参数的模板化类的单个方法中所述)

然而,当具有多个模板参数的较大模板类中,当它们中的每一个影响单个函数时,这变得令人厌烦.使用N个参数,您需要专门化2 ^ N次!

但是,使用C++ 11我认为可能有一个更优雅的解决方案,但我不知道如何处理它.也许不知怎的enable_if?有任何想法吗?

Man*_*726 13

除了Torsten提出的基于继承的解决方案之外,您还可以使用std::enable_if默认函数模板参数来启用/禁用该函数的某些特化.

例如:

template<typename T>
struct comparer
{
    template<typename U = T ,
    typename std::enable_if<std::is_floating_point<U>::value>::type* = nullptr>
    bool operator()( U lhs , U rhs )
    {
        return /* floating-point precision aware comparison */;
    }

    template<typename U = T ,
    typename std::enable_if<!std::is_floating_point<U>::value>::type* = nullptr>
    bool operator()( U lhs , U rhs )
    {
        return lhs == rhs;
    } 
};
Run Code Online (Sandbox Code Playgroud)

我们利用SFINAE来禁用/启用函数的不同"特化",具体取决于模板参数.因为SFINAE只能依赖于函数参数而不是类参数,所以我们需要一个函数的可选模板参数,它接受类的参数.

我更喜欢这种解决方案而不是继承,因为:

  • 它需要更少的打字.减少输入可能会减少错误.
  • 所有专业都写在课堂内.这种编写特化的方法包含原始类中的所有特化,并使特化看起来像函数重载,而不是基于棘手的模板的代码.

但是对于没有实现可选功能模板参数的编译器(如VS2012中的MSVC),此解决方案不起作用,您应该使用基于继承的解决方案.

编辑:您可以使用其他函数委托工作来覆盖模板函数的非实现的default-function-template-parameters:

template<typename T>
struct foo
{
private:
    template<typename U>
    void f()
    {
        ...
    }

public:
    void g()
    {
        f<T>();
    }
};
Run Code Online (Sandbox Code Playgroud)

当然,编译器可以轻松地内联g()丢弃包装调用,因此不会对此替代方案造成性能损失.