类模板部分专业化和混乱的东西混淆班级成员专业化

时间:2017-02-14 10:51:59

标签: c++ templates partial-specialization

这里我定义了一个类模板Foo,专门化它的成员函数,然后为该类提供部分特化:

// this is Foo_0
template<typename T, typename S>
class Foo {
public:
    void operator()() {
        std::cout << "Foo_0\n";
    }
    template<typename R>
    void bar(R) {
        std::cout << "I'm from Foo_0\n";
    }
};
template<>
template<>
void Foo<double, int>::bar(double) {
    std::cout << "Now I'm specialized!\n";
}

// this is Foo_1
template<typename T>
class Foo<T, int> {
public:
    void operator()() {
        std::cout << "Foo_1\n";
    }
};

我在VS2015上实例化了这样的Foo:

Foo<double, int> f;
f();

令人惊讶的是,f()打印&#34; Foo_0&#34;,这意味着不选择部分专用模板Foo_1。 什么甚至更奇怪,当我评论Foo :: bar(double)的特化时,f()打印&#34; Foo_1&#34;!

然后我测试一下:

Foo<int, int> f;
f();

这一次,f()还打印&#34; Foo_1&#34;,应用了类专业化。

因此,成员bar()的特化似乎会影响类模板的部分特化的应用。真的吗?为什么它会像这样工作?

1 个答案:

答案 0 :(得分:3)

<div class="w-100"></div>

的明确专业化
Foo<double, int>::bar

导致隐式实例化template<> template<> void Foo<double, int>::bar(double) { std::cout << "Now I'm specialized!\n"; } 。这是比部分专业Foo<double, int>更好的匹配,因此除非您注释掉Foo<T, int>的特化,否则您将获得Foo_0而不是Foo_1

您可以做的是将bar作为常规重载成员函数移动到通用类模板bar(double)

Foo<T, S>

现在您将获得template<class T, class S> class Foo { // as before void bar(double) { std::cout << "Now I'm overloaded!\n"; } }; live example。请注意,您将无法再拨打Foo_1。如果您需要,那么您还需要将Foo<double, int>::bar(double)成员添加到部分特化bar