函数模板的显式特化(它是类模板的成员)产生“不允许部分特化”错误,为什么?

时间:2017-07-29 04:06:50

标签: c++ templates explicit-specialization

我正在处理Visual Studio 2015 community edition

让我说我有一个这样简单的类:
(以下示例“应该”是可编译的,因为它包含所有必要的内容,不幸的是,它会产生错误)。

#include <stdexcept>

template <typename T>
class class_foo
{
// members, methods, constructors. not important stuff...

// helper functions:
private:
    class tag_aaa {}; // to resolve few things at compile-time, not run-time.
    class tag_bbb {}; // - || -

    template <typename tag>
    void erase();

    // for some reason this is not interpreted as an error by my compiler:
    template<>
    void erase<tag_aaa>();

    template<>
    void erase<tag_bbb>();
};

// catch-all-do-nothing "version"
// well, catch-all-throw-an-exception because call to this function is an obvious error.
// that should never occur.
template <typename T>
template <typename tag> inline
void class_foo<T>::erase()
{
    throw std::runtime_error("Very weird error...");
}

template <>
template <typename T> inline
void class_foo<T>::erase<class_foo<T>::tag_aaa>()
{
    // do some stuff... 
}

template <>
template <typename T> inline
void class_foo<T>::erase<class_foo<T>::tag_bbb>()
{
    // do some stuff... 
}

int main()
{
    class_foo<double> bar;

    return 0;
}

错误:

1>D:/develop/workspace/visual_studio/nevada_test_site/source/workspace/nevada_test_site/start.cu(36): error : partial specialization of class "class_foo<T>::erase<class_foo<T>::tag_aaa> [with T=T]" is not allowed

1>D:/develop/workspace/visual_studio/nevada_test_site/source/workspace/nevada_test_site/start.cu(43): error : partial specialization of class "class_foo<T>::erase<class_foo<T>::tag_bbb> [with T=T]" is not allowed

1>D:/develop/workspace/visual_studio/nevada_test_site/source/workspace/nevada_test_site/start.cu(51): warning : variable "bar" was declared but never referenced

我认为自己是一名初级爱好者程序员,所以我当然错了,但我相信erase<class_foo<T>::tag_aaa>()erase<class_foo<T>::tag_bbb>()都是template <typename tag> void erase();函数的明确特化。因此,他们是允许的。我相信这个错误是由于一些错误的语法,但我找不到错误。

问题:

  • 我想做什么,允许吗?
  • 如果是的话,我做错了什么?
  • 如果是,那么专门化这个函数的正确语法是什么(erase)?

1 个答案:

答案 0 :(得分:2)

它看起来像模板函数的完全特化,但它仍然是部分特化,因此编译错误。

为什么?好吧,看看这个专业化:

template <>
template <typename T>
inline void class_foo<T>::erase<class_foo<T>::tag_bbb>() {
    // do some stuff...
}

你说它是一个明确的专业化,但仍然有一个模板参数需要填充!参数T尚未知晓。所以专业化......仍然是模板?这是一个部分专业化!

由于许多原因,不允许对功能进行部分专业化。其中之一就是它在重载方面不能很好地发挥作用。

要有效地专门化该功能,您必须不要保留任何模板参数,如下所示:

template<>
template<>
inline void class_foo<int>::erase<class_foo<int>::tag_bbb>() {
    // do some stuff...
}

但它不是你想要的。

以下是我如何解决此问题的方法。使用重载而不是专门化:

template<typename T>
struct class_foo {

private:
    struct tag_aaa {};
    struct tag_bbb {};

    void erase(tag_aaa) {
        // Stuff when tag_aaa
    }

    void erase(tag_bbb) {
        // Stuff when tag_bbb
    }
};

而不是像这样调用:

erase<tag_aaa>(); // with specialization

你必须像那样调用它:

erase(tag_aaa{}); // with overloading