如何区分模板的重载与非类型参数?

wor*_*tor 5 c++ templates overloading

以下是两个模板函数,它们的模板参数不同.其余参数完全相同.

    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;
    }
Run Code Online (Sandbox Code Playgroud)

当我试图像这样打电话给他们

template_const<true>(a,b)
Run Code Online (Sandbox Code Playgroud)

要么

template_const<123>(a,b)
Run Code Online (Sandbox Code Playgroud)

编译器告诉我调用是不明确的.我怎么称呼这两个功能?

Luc*_*lle 6

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

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

因此,编译器不能选择其中一个,因此会产生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);
}
Run Code Online (Sandbox Code Playgroud)

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

#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);
}
Run Code Online (Sandbox Code Playgroud)