【问题标题】:How can I distinguish overloads of templates with non-type parameters?如何区分具有非类型参数的模板重载?
【发布时间】:2013-06-26 07:07:44
【问题描述】:

这里有两个模板函数,它们的区别仅在于它们的模板参数。其余参数完全相同。

    template<int module>
    void template_const(int &a,int & b){
            a = a & module;
            b = b % module;
    }

    template<bool x>
    void template_const(int &a,int & b){
            int w;
            if (x){
                    w = 123;
            }
            else w = 512;
            a = a & w;
            b = b % w;
    }

当我尝试这样称呼他们时

template_const<true>(a,b)

template_const<123>(a,b)

编译器告诉我调用不明确。如何调用这两个函数?

【问题讨论】:

    标签: c++ templates overloading


    【解决方案1】:

    正如@jogojapan 指出的那样,问题在于编译器无法对这两个函数进行排序,即没有一个比另一个更专业。如 §14.5.6.2 中所述,当对重载函数模板的调用不明确时,编译器会使用各种重载之间的偏序来选择最专业的一个。

    为了对重载进行排序,编译器对它们中的每一个进行转换并执行模板参数推导,以查看一个是否比另一个更专业(this answer 末尾有一个简短的解释)。在您的情况下,这两个重载是等效的(或不可比较的):template&lt;int&gt; void template_const(int &amp;,int &amp;) 并不比 template&lt;bool&gt; void template_const(int &amp;, int &amp;) 更专业,反之亦然。

    因此,编译器无法选择其中一个,从而产生ambiguous call 错误。


    如果您可以明确指定要传递的参数的类型,则可以使用部分模板专业化,如下所示:

    template<typename T, T param>
    struct template_const_impl;
    
    template <int module>
    struct template_const_impl<int, module>
    {
        static void apply(int &a, int &b)
        {
            a = a & module;
            b = b % module;
        }
    };
    
    template<bool x>
    struct template_const_impl<bool, x>
    {
        static void apply(int &a, int &b)
        {
            const int w = x ? 123 : 512;
            a = a & w;
            b = b % w;
        }
    };
    
    template <typename T, T param>
    void template_const(int &a, int &b)
    {
        return template_const_impl<T, param>::apply(a, b);
    }
    
    int main()
    {
        int i = 512, j = 256;
        template_const<int, 123>(i, j);
        template_const<bool, true>(i, j);
    }
    

    这并不理想,但它认为没有更清洁的解决方案,除非您可以使用 C++11 并且愿意依赖一些宏,在这种情况下您可以稍微简化调用代码(采取的想法来自@Nawaz 在this answer):

    #define TEMPLATE_CONST(x) template_const<decltype(x), x>
    
    int main()
    {
        int i = 512, j = 256;
        TEMPLATE_CONST(123)(i, j);
        TEMPLATE_CONST(true)(i, j);
    }
    

    【讨论】:

      【解决方案2】:

      我不认为它会像这样工作。您有具有相同参数类型的重载。可能你最终将不得不给他们不同的名字,并在你尝试的时候给他们打电话。

      【讨论】:

      • 但是他们通过了编译。模板在实际调用时是否编译?
      • 编译器告诉你调用是模棱两可的,对吧?那不叫通过编译。当然,一切都是在编译时编译的,模板仅在请求实例化时才编译。
      • 确实不会这样工作。但问题不仅仅是函数参数类型相同的事实。您可以仅通过更改模板参数(而不是函数参数类型)来重载函数模板。这里的问题是模板重载解析期间使用的消歧机制将boolint 视为相等(与用于普通函数参数的解析机制不同)。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-03-29
      • 1970-01-01
      • 1970-01-01
      • 2023-01-25
      • 2018-05-15
      • 1970-01-01
      • 2014-09-16
      相关资源
      最近更新 更多