Явная специализация шаблона функции (которая является членом шаблона класса) приводит к ошибке "частичная специализация не допускается", почему?

Я работаю над 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 ответ

Решение

Это похоже на полную специализацию функции шаблона, но это все еще частичная специализация, следовательно, ошибка компиляции.

Почему это? Ну, посмотрите на эту специализацию:

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
Другие вопросы по тегам