Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/templates/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在大模板类中专门化单个方法 C++中,如果想在模板类中部分地专门化一个方法,则必须专门化整个类(如在上面所述)_C++_Templates_C++11 - Fatal编程技术网

在大模板类中专门化单个方法 C++中,如果想在模板类中部分地专门化一个方法,则必须专门化整个类(如在上面所述)

在大模板类中专门化单个方法 C++中,如果想在模板类中部分地专门化一个方法,则必须专门化整个类(如在上面所述),c++,templates,c++11,C++,Templates,C++11,但是,在具有多个模板参数的较大模板类中,当每个模板参数都影响单个函数时,这会变得很烦人。使用N个参数,您需要专门化类2^N次 然而,对于C++11,我认为可能有一个更优雅的解决方案,但我不确定如何实现它。如果,可能会以某种方式启用?有什么想法吗?一种解决方案是从函数转发,您希望重载到一些依赖于类模板参数的实现: template < typename T > struct foo { void f(); }; template < typename T > str

但是,在具有多个模板参数的较大模板类中,当每个模板参数都影响单个函数时,这会变得很烦人。使用N个参数,您需要专门化类2^N次


然而,对于C++11,我认为可能有一个更优雅的解决方案,但我不确定如何实现它。如果,可能会以某种方式启用?有什么想法吗?

一种解决方案是从函数转发,您希望重载到一些依赖于类模板参数的实现:

template < typename T >
struct foo {
   void f();
};

template < typename T >
struct f_impl {
    static void impl()
    {
        // default implementation
    }
};

template <>
struct f_impl<int> {
    static void impl()
    {
         // special int implementation
    }
};

template < typename T >
void foo< T >::f()
{
    f_impl< T >::impl();
}
模板
结构foo{
无效f();
};
模板
结构f_impl{
静态void impl()
{
//默认实现
}
};
模板
结构f_impl{
静态void impl()
{
//特殊int实现
}
};
模板
void foo::f()
{
f_impl::impl();
}
或者只使用私有函数,使用模板参数调用它们并重载它们

template < typename T >
class foo {
public:
    void f()
    {
        impl(T());
    }
private:
    template < typename G >
    void impl( const G& );
    void impl( int );
};
模板
福班{
公众:
void f()
{
impl(T());
}
私人:
模板
无效impl(const G&);
无效impl(int);
};
或者,如果它实际上只是一种特殊情况,具有非常特殊的类型,则只需在实现中查询该类型。

如果:

#include <iostream>
#include <type_traits>

template <typename T>
class A {
    private:
    template <typename U>
    static typename std::enable_if<std::is_same<U, char>::value, char>::type
    g() {
        std::cout << "char\n";
        return char();
    }

    template <typename U>
    static typename std::enable_if<std::is_same<U, int>::value, int>::type
    g() {
        std::cout << "int\n";
        return int();
    }

    public:
    static T f() { return g<T>(); }
};

int main(void)
{
    A<char>::f();
    A<int>::f();
    // error: no matching function for call to ‘A<double>::g()’
    // A<double>::f();
    return 0;
}
#包括
#包括
模板
甲级{
私人:
模板
静态类型名称std::enable_if::type
g(){

std::cout除了Torsten提出的基于继承的解决方案外,还可以使用和默认函数模板参数来启用/禁用函数的某些专门化

例如:

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;
    } 
};
模板
结构比较器
{
模板
布尔运算符()
{
return/*浮点精度感知比较*/;
}
模板::类型*=nullptr>
布尔运算符()
{
返回lhs==rhs;
} 
};
我们利用禁用/启用函数的不同“专门化”,具体取决于模板参数。由于SFINAE只能依赖函数参数,而不能依赖类参数,因此我们需要为函数提供一个可选的模板参数,该参数采用类的参数

与基于继承的解决方案相比,我更喜欢此解决方案,因为:

  • 它需要更少的输入。更少的输入可能会导致更少的错误
  • 所有专门化都是在类内部编写的。这种编写专门化的方法保存了原始类内部的所有专门化,并使专门化看起来像函数重载,而不是复杂的基于模板的代码
但对于未实现可选函数模板参数的编译器(如VS2012中的MSVC),此解决方案不起作用,您应该使用基于继承的解决方案

编辑:您可以浏览未实现的默认函数模板参数,这些参数将模板函数包装为其他委托工作的函数:

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

public:
    void g()
    {
        f<T>();
    }
};
模板
结构foo
{
私人:
模板
void f()
{
...
}
公众:
void g()
{
f();
}
};

当然,编译器可以轻松地内联
g()
丢弃包装调用,因此这种替代方法不会影响性能。

标记分派通常是一种干净的方法

在基本方法中,使用traits类确定要调用的方法的子版本。这将生成一个描述决策结果的类型(称为标记)

然后完美地转发到implementation子版本,传递一个标记类型的实例。重载解析生效,并且只有您想要的implementation被实例化和调用


基于参数类型的重载解析是处理分派的一种不那么疯狂的方法,因为如果
在使用点上是脆弱的、复杂的,那么
enable\u会变得非常复杂,如果你有3个以上的重载,那么会有奇怪的情况,可能会让你惊讶于奇妙的编译错误。

也许我错了,但选择了最好的anwser pr由MUN33626排除的错误将不会编译。两个运算符重载都有“强”>相同的签名< /强>。考虑最佳的ANWSER < /P>
另外,我会发表评论,但声誉不够,抱歉

我认为您忘记添加
U
template参数的默认值。否则您的调用应该是
a::f();
,这是没有意义的。@Manu343726 f正在委托给g(不需要默认值)嗯,我从来没有想过将函数模板包装成不依赖于可选模板参数。感谢中的每次讨论,您可以将enable_if作为第二个方法模板参数(在U=T之后)而不是函数返回类型。这使函数签名更简洁,也应该与构造函数一起工作。@CygnusX1除此之外,我知道这种方式,我总是使用返回类型方式。但是,这种解决方案更通用(如您所说,与构造函数一起工作),所以我不知道为什么我总是喜欢返回类型的方式…:)当::impl()引用主类时,这会变得有点糟糕-您需要传递'This'指针,并使side struct成为朋友。此外,字段的存在可能在某种程度上取决于t(这就是您想要专门化的原因)。如果您只是重载私有中的所有函数变量,它们可能会在某些情况下无法编译。是的,第一种解决方案有其局限性。在第二种解决方案中,您不必重载所有可能的模板类参数,即第一个impl()函数的行为类似于catch all default。如果根据模板类参数需要不同的“字段”,通常的解决方案是,将它们放在基类中,并完全专门化该基类