Я работаю над 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
)?Это похоже на полную специализацию функции шаблона, но это все еще частичная специализация, следовательно, ошибка компиляции.
Почему это? Ну, посмотрите на эту специализацию:
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
Других решений пока нет …