以下是一个简单的模板部分特化:

// #1
template <typename T, T n1, T n2>
struct foo {
    static const char* scenario() {
        return "#1 the base template";
    }
};

// #2
// partial specialization where T is unknown and n1 == n2
template <typename T, T a>
struct foo<T, a, a> {
    static const char* scenario() {
        return "#2 partial specialization";
    }
};
以下主要内容在g++ (6.1)clang++ (3.8.0)上得到不同的结果:
extern const char HELLO[] = "hello";
double d = 2.3;

int main() {
    cout <<   foo<int, 1, 2>                    ::scenario() << endl;
    cout <<   foo<int, 2, 2>                    ::scenario() << endl;
    cout <<   foo<long, 3, 3>                   ::scenario() << endl;
    cout <<   foo<double&, d, d>                ::scenario() << endl;
    cout <<   foo<double*, &d, &d>              ::scenario() << endl;
    cout <<   foo<double*, nullptr, nullptr>    ::scenario() << endl;
    cout <<   foo<int*, nullptr, nullptr>       ::scenario() << endl;
    cout <<   foo<nullptr_t, nullptr, nullptr>  ::scenario() << endl;
    cout <<   foo<const char*, HELLO, HELLO>    ::scenario() << endl;
}
在g++和clang上的结果# | The code | g++ (6.1) | clang++ (3.8.0) |1 | foo<int, 1, 2> | #1 as expected | #1 as expected |2 | foo<int, 2, 2> | #2 as expected | #2 as expected |3 | foo<long, 3, 3> | #2 as expected | #2 as expected |4 | foo<double&, d, d> | #1 -- why? | #2 as expected |5 | foo<double*, &d, &d> | #2 as expected | #2 as expected |6 | foo<double*, nullptr, nullptr> | #2 as expected | #1 -- why? |7 | foo<int*, nullptr, nullptr> | #2 as expected | #1 -- why? |8 | foo<nullptr_t, nullptr, nullptr> | #2 as expected | #1 -- why? |9 | foo<const char*, HELLO, HELLO> | #2 as expected | #2 as expected |哪一个是对的?
代码:http://coliru.stacked-crooked.com/a/45ba16c9f021fd84

最佳答案

#4格式不正确,我很惊讶它可以编译。一方面,不能将double用作非类型模板参数。另一方面,类模板使用与函数模板相同的规则进行部分排序。该标准提供了为执行排序而生成的“虚构”函数的示例:

template<int I, int J, class T> class X { };
template<int I, int J> class X<I, J, int> { }; // #1
template<int I>        class X<I, I, int> { }; // #2
template<int I, int J> void f(X<I, J, int>); // A
template<int I>        void f(X<I, I, int>); // B

对于您的示例,它看起来像这样:
template <typename T, T n1, T n2>
struct foo {
};

template <typename T, T n1, T n2>
void bar(foo<T, n1, n2>)
{
    std::cout << "a";
}

template <typename T, T a>
void bar(foo<T, a, a>)
{
    std::cout << "b";
}

模板参数推导用于确定哪个功能比另一个功能更专业。应该将double&推导为double,因此这两个特化应相等,即bar(foo<double&, d, d>{});也是模棱两可的。 Lo看到GCC和Clang提示:



同样,如果删除引用,他们俩都会正确地提示将double用作非类型模板参数。

我将不测试其余部分,但您可能会发现类似的结果。

关于c++ - 整数非类型参数和非整数非类型的模板部分特化,g++和clang之间的区别,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/37369129/

10-13 07:09