【问题标题】:Function template overloading - partial specialization函数模板重载 - 部分特化
【发布时间】:2018-03-20 02:04:12
【问题描述】:

我有 2 个遵循类似模式的课程:

Foo.h

// header guard here 

class Foo {
public:
    Foo() = delete;

    static foo1& getFoo1( Param a, Param b, Param c ) {
        // code...
    }

    static foo2& getFoo2( Param a, Param b, Param c ) {
        // code...
    }

    // generic function to return appropriate Foo Type based on template argument 
    template<class FooType>
    static FooType& getFoo( Param a, Param b, Param c );
};

#endif

Foo.cpp

#include <Foo.h>

// specializations of getFoo() for each type
template<>
foo1& Foo::getFoo( Param a, Param b, Param c ) {
    return getFoo1( a, b, c );
}

template<>
foo2& Foo::getFoo( Param a, Param b, Param c ) {
    return getFoo2( a, b, c );
}

上面的 Foo 编译得很好。另一方面,Bar 具有与上述Foo 相似的结构或模式;唯一的区别是它是静态的getBar1()getBar2() 等不仅仅是普通功能;它们是函数模板。

Bar.h

// header guard

class Bar {
public:
    Bar() = delete;

    template<class IntType = int>
    static bar1<IntType>& getBar1( IntType a, IntType b ) {
        // code...
    }

    template<class RealType = double>
    static bar2<RealType>& getBar2( RealType a, RealType b ) {
        // code...
    }

    template<class IntType = int>
    static bar3<IntType>& getBar3( IntType a ) {
        // code...
    }

    template<class RealType = double>
    static bar4<RealType>& getBar4( RealType a ) {
        // code...
    }

    // ...

    template<class RealType = double>
    static bar12<RealType>& getBar12() {
        // code...
    }

    template<class RealType = double, class A, class B>
    static bar12&<RealType>& getBar12( A a1, A a2, B b1 ) {
        // code...
    }

    template<class RealType = double, class X>
    static bar12&<RealType>& getBar12( std::initialize_list<double> list, X x ) {
        // code...
    }

    template<class RealType = double, class X>
    static bar12&<RealType>& getBar12( std::size_t size, RealType a, RealType b, X x ) {
        // code..
    }

    // Here is where I start to get into problems:
    // I'm trying to do something similar to what I've done above in Foo for a generic function template.
    template<typename Type, template<typename> class BarType, class... FuncParams>
    static BarType<Type>& getBar( FuncParams... params );

}; 

#endif

Bar.cpp

#include "Bar.h"

// specializations of getBar() for each type
template<typename Type, class... FuncParams>
bar1<Type>& Bar::getBar( FuncParams... params ) {
    return getBar1( params... );
}

template<typename Type, class... FuncParms>
bar2<Type>& Bar::getBar( FuncParams... params ) {
    return getBar2( params... );
}

为什么当我开始添加一个类类型时,它是一个类模板;一切似乎都破裂了。上面的第一个类编译并返回适当的Foo。但是,在第二类 Bar 中,我不断收到编译器错误,即函数定义与现有声明不匹配。

这个问题与这里的这个问题有关:Specializing and or Overloading member function templates with variadic parameters

这个问题专门关于为什么一个编译而另一个不编译。

【问题讨论】:

    标签: c++ c++11 templates variadic-templates partial-specialization


    【解决方案1】:

    上面的第一个类编译并返回适当的Foo

    是的,因为

    template<>
    foo1& Foo::getFoo( Param a, Param b, Param c ) {
        return getFoo1( a, b, c );
    }
    

    它是模板方法getFoo()完整特化

    template<class FooType>
    static FooType& getFoo( Param a, Param b, Param c );
    

    FooType 类型固定为foo1

    您可以对模板函数(或方法)进行完整特化。

    但是,在第二类 Bar 中,我不断收到编译器错误,即函数定义与现有声明不匹配。

    当然。

    因为您正在尝试部分专门化模板方法getBar()

    template<typename Type, template<typename> class BarType, class... FuncParams>
    static BarType<Type>& getBar( FuncParams... params );
    

    BarType 修复为bar1

    template<typename Type, class... FuncParams>
    bar1<Type>& Bar::getBar( FuncParams... params ) {
        return {};//getBar1( params... );
    }
    

    但您不能部分专门化模板函数/方法。这是语言所禁止的。

    如果你想要类似的东西,你必须通过结构(或类)的部分特化。

    --- 编辑---

    OP 询问

    您说,“您必须通过结构(或类)的部分特化。”好的;所以有一个解决方法:你能提供一个小的基本示例吗?

    有很多方法可以使用结构(类)的部分特化来绕过函数/方法的非部分特化限制。

    在下面的基本示例中,我提出了一个模板foo 结构和一个模板func() 方法。 foo 的单个模板参数是func() 返回的类型; func() 的可变参数模板类型列表是参数类型的列表。

    但是你可以在不同的模式下玩这个游戏。

    #include <iostream>
    
    template <typename>
    struct bar1
     { template <typename ... Args> bar1 (Args && ...) { } };
    
    template <typename>
    struct bar2
     { template <typename ... Args> bar2 (Args && ...) { } };
    
    template <typename>
    struct foo;
    
    template <typename T>
    struct foo<bar1<T>>
     {
       template <typename ... Args>
       static bar1<T> func (Args && ... as)
        { return { std::forward<Args>(as)... }; }
     };
    
    template <typename T>
    struct foo<bar2<T>>
     {
       template <typename ... Args>
       static bar2<T> func (Args && ... as)
        { return { std::forward<Args>(as)... }; }
     };
    
    int main()
     {
       foo<bar1<int>>::func(1, "two", 3.0);
       foo<bar2<long>>::func(4.0f, "five", 6L);
     }
    

    【讨论】:

    • 我认为偏特化应该写成Bar::getBar&lt;Blah, Blah&gt;(){...}。 IMO 在这种情况下,编译器只是试图找到匹配的声明但失败了。
    • 感谢您的详细解释。这就是我遇到麻烦的地方;我不知道我的语法是否不正确,或者是否无法完成。你说,“你必须通过结构(或类)的部分特化。”好的;所以有一个解决方法:你能提供一个小的基本示例吗?
    • @dontpanic - C++ 不允许函数/方法的部分特化
    • @FrancisCugler - 用一个小例子改进了答案;希望这会有所帮助。
    • @max66 是的。我的意思是这样写根本不是部分专业化。
    猜你喜欢
    • 2011-12-25
    • 2011-06-27
    • 1970-01-01
    • 1970-01-01
    • 2013-02-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多