Когда вы создали экземпляр Test<void>
, вы также создали объявления всех его функций-членов. Это просто базовая реализация. Какие заявления это дает? Примерно так:
void execute(void);
void execute(<ill-formed> t);
Если вы ожидали, что SFINAE бесшумно устранит неправильно сформированную перегрузку, вам следует помнить, что буква S обозначает «замену». Подстановка аргументов шаблона в параметры (члена) шаблона функции . Ни execute
не является шаблоном функции-члена. Обе они являются регулярными функциями-членами специализации шаблона.
Вы можете исправить это несколькими способами. Одним из способов может быть создание этих двух шаблонов, правильное выполнение SFINAE и разрешение перегрузки. @ YSC уже показывает вам, как.
Другой способ - использовать вспомогательный шаблон. Таким образом, вы получите свою первоначальную цель, чтобы одна функция-член существовала в одно время.
template<typename T>
struct TestBase {
void execute(T t) { }
};
template<>
struct TestBase<void> {
void execute() { }
};
template<class T>
struct Test : private TestBase<T> {
using TestBase<T>::execute;
};
Вы можете выбрать тот, который лучше всего подходит для ваших нужд.
Для решения вашей правки. Я думаю, что второй подход на самом деле лучше соответствует вашим потребностям.
template<typename T>
struct TestBase : Base {
void execute(T t) override { }
};
template<>
struct TestBase<void> : Base {
void execute() override { }
};
TestBase
- средний человек, который выполняет то, за чем вы, похоже, стремитесь.